mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-10 19:57:43 +02:00
Generated
+9
-9
@@ -1736,8 +1736,8 @@ importers:
|
||||
specifier: ~22.8.7
|
||||
version: 22.8.8
|
||||
electron:
|
||||
specifier: ^35.0.3
|
||||
version: 35.0.3
|
||||
specifier: ^36.3.1
|
||||
version: 36.3.1
|
||||
electron-builder:
|
||||
specifier: ^25.1.8
|
||||
version: 25.1.8
|
||||
@@ -4172,7 +4172,7 @@ packages:
|
||||
version: 0.0.0
|
||||
|
||||
'@rush-temp/desktop-1@file:projects/desktop-1.tgz':
|
||||
resolution: {integrity: sha512-rsHmRGdl06oTqUIcR9dPSRKa4Fr+aiBNUfdnskyM/yzol/YQcaOhrOmStUArrr+l0ey5qSVX40GNrRuDK5RQJA==, tarball: file:projects/desktop-1.tgz}
|
||||
resolution: {integrity: sha512-+3xHE79pZH3p6fzQkqin/6vH7inebwonxQgQiODe0wVygulmUFPWwFFEI4rtraGZYiivKUmJ5zCd+dCckLu6KQ==, tarball: file:projects/desktop-1.tgz}
|
||||
version: 0.0.0
|
||||
|
||||
'@rush-temp/desktop-preferences-assets@file:projects/desktop-preferences-assets.tgz':
|
||||
@@ -4188,7 +4188,7 @@ packages:
|
||||
version: 0.0.0
|
||||
|
||||
'@rush-temp/desktop@file:projects/desktop.tgz':
|
||||
resolution: {integrity: sha512-nfD+5Z3H2YZOhYd17GM4bArHHPFx7Jkxnf65ODiy05bVFUHbj3YaC0btFbq5l83NFWL94YL3yPvXe1P87MqI0w==, tarball: file:projects/desktop.tgz}
|
||||
resolution: {integrity: sha512-ksJbenEj9NJb3b0bGinpUWssVjPWzaWfUEy+kRMqG1gBaFMqhtqBXNNuyLbtAywAaX9uMqSosGCE/E265qRfAw==, tarball: file:projects/desktop.tgz}
|
||||
version: 0.0.0
|
||||
|
||||
'@rush-temp/devmodel-resources@file:projects/devmodel-resources.tgz':
|
||||
@@ -8512,8 +8512,8 @@ packages:
|
||||
electron-windows-badge@1.1.0:
|
||||
resolution: {integrity: sha512-hWFbUk9u3fQHcKzTAcjZAN7XH9bL9oH9g20RRDU/DVDNqdMI03GzlBZfR/R8R1krYu9AT4biLqSCAxnt9LMAfA==}
|
||||
|
||||
electron@35.0.3:
|
||||
resolution: {integrity: sha512-kjQAYEWXSr2TyK19IZoF85dzFIBaYuX7Yp/C+34b5Y/jmI2z270CGie+RjmEGMMitsy0G8YJKftukhYMuWlK6g==}
|
||||
electron@36.3.1:
|
||||
resolution: {integrity: sha512-LeOZ+tVahmctHaAssLCGRRUa2SAO09GXua3pKdG+WzkbSDMh+3iOPONNVPTqGp8HlWnzGj4r6mhsIbM2RgH+eQ==}
|
||||
engines: {node: '>= 12.20.55'}
|
||||
hasBin: true
|
||||
|
||||
@@ -18113,7 +18113,7 @@ snapshots:
|
||||
'@vercel/webpack-asset-relocator-loader': 1.7.4
|
||||
cross-env: 7.0.3
|
||||
dotenv: 16.0.3
|
||||
electron: 35.0.3
|
||||
electron: 36.3.1
|
||||
electron-builder: 25.1.8
|
||||
electron-squirrel-startup: 1.0.1
|
||||
node-loader: 2.0.0(webpack@5.97.1)
|
||||
@@ -18229,7 +18229,7 @@ snapshots:
|
||||
css-loader: 5.2.7(webpack@5.97.1)
|
||||
dotenv: 16.0.3
|
||||
dotenv-webpack: 8.0.1(webpack@5.97.1)
|
||||
electron: 35.0.3
|
||||
electron: 36.3.1
|
||||
electron-context-menu: 4.0.4
|
||||
electron-log: 5.1.7
|
||||
electron-squirrel-startup: 1.0.1
|
||||
@@ -31556,7 +31556,7 @@ snapshots:
|
||||
|
||||
electron-windows-badge@1.1.0: {}
|
||||
|
||||
electron@35.0.3:
|
||||
electron@36.3.1:
|
||||
dependencies:
|
||||
'@electron/get': 2.0.3
|
||||
'@types/node': 22.13.12
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"node-loader": "~2.0.0",
|
||||
"cross-env": "~7.0.3",
|
||||
"typescript": "^5.3.3",
|
||||
"electron": "^35.0.3",
|
||||
"electron": "^36.3.1",
|
||||
"@types/node": "~20.11.16",
|
||||
"electron-builder": "^25.1.8",
|
||||
"@electron/notarize": "^2.3.2"
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"typescript": "^5.3.3",
|
||||
"ts-node": "^10.8.0",
|
||||
"ts-node-dev": "^2.0.0",
|
||||
"electron": "^35.0.3",
|
||||
"electron": "^36.3.1",
|
||||
"@types/node": "~20.11.16",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import client, { clientId } from '@hcengineering/client'
|
||||
import { MeasureMetricsContext, WorkspaceIds, type BackupClient, type Client } from '@hcengineering/core'
|
||||
import { addLocation, getResource, setMetadata } from '@hcengineering/platform'
|
||||
import WebSocket from 'ws'
|
||||
|
||||
import {
|
||||
backup,
|
||||
createFileBackupStorage
|
||||
} from '@hcengineering/server-backup'
|
||||
import { dialog, type BrowserWindow } from 'electron'
|
||||
|
||||
let runningBackup: {
|
||||
notify: (command: string, ...args: any[]) => void
|
||||
} | undefined
|
||||
|
||||
export async function createClient (
|
||||
transactorUrl: string,
|
||||
token: string
|
||||
): Promise<Client & BackupClient> {
|
||||
// We need to override default factory with 'ws' one.
|
||||
// eslint-disable-next-line
|
||||
setMetadata(client.metadata.UseBinaryProtocol, true)
|
||||
setMetadata(client.metadata.UseProtocolCompression, true)
|
||||
setMetadata(client.metadata.ConnectionTimeout, 0)
|
||||
setMetadata(client.metadata.ClientSocketFactory, (url) => {
|
||||
return new WebSocket(url) as any
|
||||
})
|
||||
addLocation(clientId, () => import('@hcengineering/client-resources'))
|
||||
|
||||
const clientFactory = await getResource(client.function.GetClient)
|
||||
return (await clientFactory(token, transactorUrl)) as unknown as Client & BackupClient
|
||||
}
|
||||
|
||||
async function doBackup (dirName: string, token: string, endpoint: string, wsIds: WorkspaceIds, notify: (command: string, ...args: any[]) => void, backupHugeFiles: boolean): Promise<void> {
|
||||
notify('backup', 0)
|
||||
const ctx = new MeasureMetricsContext('backup', {})
|
||||
|
||||
const storage = await createFileBackupStorage(dirName)
|
||||
const client = await createClient(endpoint, token)
|
||||
try {
|
||||
ctx.info('do backup', { ...wsIds, endpoint })
|
||||
await backup(ctx, endpoint, wsIds, storage, {
|
||||
force: true,
|
||||
skipDomains: [],
|
||||
timeout: 0,
|
||||
connectTimeout: 60 * 1000,
|
||||
blobDownloadLimit: backupHugeFiles ? 10240 : 50,
|
||||
token,
|
||||
skipBlobContentTypes: [],
|
||||
keepSnapshots: 7 * 14,
|
||||
isCanceled: (): boolean => {
|
||||
return runningBackup == null
|
||||
},
|
||||
progress: async (value: number): Promise<void> => {
|
||||
notify('backup', value)
|
||||
},
|
||||
getConnection: async () => client
|
||||
})
|
||||
} finally {
|
||||
await client.close()
|
||||
}
|
||||
|
||||
notify('backup', 100)
|
||||
}
|
||||
|
||||
export function startBackup (window: BrowserWindow, token: string, endpoint: string, wsIds: WorkspaceIds, cmd: (command: string, ...args: any[]) => void): void {
|
||||
void dialog
|
||||
.showOpenDialog(window, {
|
||||
properties: ['openDirectory'],
|
||||
buttonLabel: 'Select a backup folder',
|
||||
message: 'Select a folder for Huly incremental backup.'
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.canceled && response.filePaths.length > 0) {
|
||||
void dialog
|
||||
.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: ['Backup....', 'Cancel'],
|
||||
defaultId: 0,
|
||||
textWidth: 500,
|
||||
title: 'Huly desktop need a confirmation for a backup process to be started...',
|
||||
message: `Huly Desktop need a confirmation for a backup process to be started....\n\n
|
||||
An incremental backup will be performed to folder:\n ${response.filePaths[0]}\n
|
||||
Backup could be canceled and resumed laterly into same location.`,
|
||||
checkboxLabel: 'Include files >= 50mb',
|
||||
checkboxChecked: false
|
||||
})
|
||||
.then((backupKind) => {
|
||||
if (backupKind.response === 1) {
|
||||
return
|
||||
}
|
||||
runningBackup = {
|
||||
notify: cmd
|
||||
}
|
||||
void doBackup(response.filePaths[0], token, endpoint, wsIds, cmd, backupKind.checkboxChecked)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
export function cancelBackup (): void {
|
||||
if (runningBackup != null) {
|
||||
runningBackup.notify('backup-cancel')
|
||||
}
|
||||
runningBackup = undefined
|
||||
}
|
||||
@@ -32,10 +32,6 @@ export const addMenus = (getWindow: () => BrowserWindow, sendCommand: (cmd: stri
|
||||
label: 'Select workspace',
|
||||
click: () => { sendCommand('select-workspace') }
|
||||
},
|
||||
{
|
||||
label: 'Backup...',
|
||||
click: () => { sendCommand('start-backup') }
|
||||
},
|
||||
{
|
||||
label: 'Logout',
|
||||
click: () => { sendCommand('logout') }
|
||||
|
||||
+26
-84
@@ -24,7 +24,6 @@ import * as path from 'path'
|
||||
|
||||
import { Config, NotificationParams } from '../ui/types'
|
||||
import { getOptions } from './args'
|
||||
import { cancelBackup, startBackup } from './backup'
|
||||
import { addMenus } from './menu'
|
||||
import { addPermissionHandlers } from './permissions'
|
||||
import autoUpdater from './updater'
|
||||
@@ -184,9 +183,13 @@ function handleAuthRedirects (window: BrowserWindow): void {
|
||||
}
|
||||
|
||||
const createWindow = async (): Promise<void> => {
|
||||
// Restore window position if available
|
||||
const restoredBounds: any = settings.get('windowBounds')
|
||||
mainWindow = new BrowserWindow({
|
||||
width: defaultWidth,
|
||||
height: defaultHeight,
|
||||
width: restoredBounds?.width ?? defaultWidth,
|
||||
height: restoredBounds?.height ?? defaultHeight,
|
||||
x: restoredBounds?.x ?? undefined,
|
||||
y: restoredBounds?.y ?? undefined,
|
||||
titleBarStyle: isMac ? 'hidden' : 'default',
|
||||
trafficLightPosition: { x: 10, y: 10 },
|
||||
roundedCorners: true,
|
||||
@@ -195,7 +198,7 @@ const createWindow = async (): Promise<void> => {
|
||||
devTools: true,
|
||||
sandbox: false,
|
||||
nodeIntegration: true,
|
||||
backgroundThrottling: false,
|
||||
// backgroundThrottling: false,
|
||||
partition: sessionPartition,
|
||||
preload: path.join(app.getAppPath(), 'dist', 'main', 'preload.js')
|
||||
}
|
||||
@@ -213,6 +216,14 @@ const createWindow = async (): Promise<void> => {
|
||||
// All other urls will be blocked.
|
||||
hookOpenWindow(mainWindow)
|
||||
|
||||
// Save window position on close
|
||||
mainWindow.on('close', () => {
|
||||
const bounds = mainWindow?.getBounds()
|
||||
if (bounds !== undefined) {
|
||||
settings.set('windowBounds', bounds)
|
||||
}
|
||||
})
|
||||
|
||||
if (isMac) {
|
||||
mainWindow.on('close', (event) => {
|
||||
// Prevent the default behavior (which would quit the app)
|
||||
@@ -315,61 +326,12 @@ ipcMain.on('set-front-cookie', function (event, host: string, name: string, valu
|
||||
void win?.webContents?.session.cookies.set(cv)
|
||||
})
|
||||
|
||||
const DEEP_LINKS_PROTOCOL = 'huly'
|
||||
/*
|
||||
Copy-paste from official tutorial for deep links
|
||||
https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app
|
||||
*/
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient(DEEP_LINKS_PROTOCOL, process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient(DEEP_LINKS_PROTOCOL)
|
||||
}
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
}
|
||||
|
||||
let deepLink = ''
|
||||
let haveDeepLinkHandler = false
|
||||
function tryToOpenDeepLink (link?: string): void {
|
||||
if (mainWindow == null || !haveDeepLinkHandler) {
|
||||
if (link != null) {
|
||||
deepLink = link
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const url = link ?? deepLink
|
||||
const httpsUrl = url.replace(`${DEEP_LINKS_PROTOCOL}://`, 'https://')
|
||||
mainWindow.webContents.send('handle-deep-link', httpsUrl)
|
||||
}
|
||||
|
||||
// Add windows / linux handler for second instance
|
||||
// This is because Windows try to open second instance from the deep link
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
if (mainWindow != null) {
|
||||
if (mainWindow.isMinimized()) mainWindow.restore()
|
||||
mainWindow.focus()
|
||||
}
|
||||
|
||||
const url = commandLine.pop()
|
||||
console.log('Opening url', url)
|
||||
|
||||
if (url != null) {
|
||||
tryToOpenDeepLink(url)
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('on-deep-link-handler', () => {
|
||||
haveDeepLinkHandler = true
|
||||
tryToOpenDeepLink()
|
||||
})
|
||||
|
||||
ipcMain.handle('get-screen-access', () => systemPreferences.getMediaAccessStatus('screen') === 'granted')
|
||||
ipcMain.handle('get-screen-sources', () => {
|
||||
return desktopCapturer.getSources({ types: ['window', 'screen'], fetchWindowIcons: true, thumbnailSize: { width: 225, height: 135 } }).then(async sources => {
|
||||
@@ -383,21 +345,9 @@ ipcMain.handle('get-screen-sources', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// MacOS implementation
|
||||
// Handle the protocol. In this case, we choose to show an Error Box.
|
||||
app.on('open-url', (event, url) => {
|
||||
if (url == null) {
|
||||
return
|
||||
}
|
||||
tryToOpenDeepLink(url)
|
||||
})
|
||||
|
||||
async function onReady (): Promise<void> {
|
||||
await createWindow()
|
||||
|
||||
const customProtocolArg = process.argv.find((arg) => arg.startsWith(`${DEEP_LINKS_PROTOCOL}://`)) ?? ''
|
||||
tryToOpenDeepLink(customProtocolArg)
|
||||
|
||||
if (serverChanged) {
|
||||
mainWindow?.webContents.send('logout')
|
||||
}
|
||||
@@ -419,15 +369,20 @@ if (isMac) {
|
||||
mainWindow.show()
|
||||
}
|
||||
})
|
||||
}
|
||||
app.on('before-quit', () => {
|
||||
if (mainWindow !== undefined && !mainWindow.isDestroyed()) {
|
||||
const bounds = mainWindow.getBounds()
|
||||
settings.set('windowBounds', bounds)
|
||||
}
|
||||
// Note: in case the app is exited by auto-updater all windows will be destroyed at this point
|
||||
if (mainWindow === undefined || mainWindow.isDestroyed()) return
|
||||
|
||||
app.on('before-quit', () => {
|
||||
// Note: in case the app is exited by auto-updater all windows will be destroyed at this point
|
||||
if (mainWindow === undefined || mainWindow.isDestroyed()) return
|
||||
|
||||
if (isMac) {
|
||||
mainWindow?.removeAllListeners('close')
|
||||
mainWindow?.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Note: it is reset when the app is relaunched after update
|
||||
let isUpdating = false
|
||||
@@ -471,16 +426,3 @@ autoUpdater.on('update-downloaded', (info) => {
|
||||
|
||||
autoUpdater.quitAndInstall()
|
||||
})
|
||||
|
||||
ipcMain.on('start-backup', (event, token, endpoint, wsIds) => {
|
||||
console.log('start backup', token, endpoint, wsIds)
|
||||
if (mainWindow != null) {
|
||||
startBackup(mainWindow, token, endpoint, wsIds, (cmd: string, ...args: any[]) => {
|
||||
mainWindow?.webContents.send(cmd, ...args)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('cancel-backup', (event) => {
|
||||
cancelBackup()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user