Skip to content

Commit 5599401

Browse files
committed
Merge branch 'staging-new'
Signed-off-by: Alexander Onnikov <[email protected]>
2 parents 94636b8 + 5fd5567 commit 5599401

File tree

538 files changed

+13609
-6495
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

538 files changed

+13609
-6495
lines changed

.vscode/launch.json

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,12 @@
104104
"UPLOAD_URL": "/files",
105105
"AI_BOT_URL": "http://localhost:4010",
106106
"STATS_URL": "http://huly.local:4900",
107-
"QUEUE_CONFIG": "localhost:19092",
107+
"QUEUE_CONFIG": "huly.local:19092",
108+
"REGION": "cockroach",
109+
"QUEUE_REGION": "cockroach",
108110
"FILES_URL": "http://huly.local:4030/blob/:workspace/:blobId/:filename",
109-
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://huly.local:4318/v1/traces"
111+
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://huly.local:4318/v1/traces",
112+
"BRANDING_PATH": "${workspaceRoot}/dev/branding.json"
110113
},
111114
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
112115
"runtimeVersion": "20",
@@ -972,25 +975,6 @@
972975
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
973976
"sourceMaps": true,
974977
"cwd": "${workspaceRoot}/services/export/pod-export"
975-
},
976-
{
977-
"name": "Msg2File",
978-
"type": "node",
979-
"request": "launch",
980-
"args": ["src/index.ts"],
981-
"env": {
982-
"ACCOUNTS_URL": "http://localhost:3000",
983-
"DB_URL": "postgresql://root@localhost:26257/defaultdb?sslmode=disable",
984-
"PORT": "9087",
985-
"SECRET": "secret",
986-
"SERVICE_ID": "msg2file-service",
987-
"STORAGE_CONFIG": "datalake|http://huly.local:4030"
988-
},
989-
"runtimeVersion": "20",
990-
"runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
991-
"sourceMaps": true,
992-
"outputCapture": "std",
993-
"cwd": "${workspaceRoot}/services/msg2file"
994978
}
995979
]
996980
}

common/config/rush/pnpm-lock.yaml

Lines changed: 106 additions & 210 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/scripts/docker.sh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ rush docker:build -p 20 \
1919
--to @hcengineering/pod-datalake \
2020
--to @hcengineering/pod-mail-worker \
2121
--to @hcengineering/pod-export \
22-
--to @hcengineering/pod-msg2file \
2322
--to @hcengineering/pod-media \
2423
--to @hcengineering/pod-preview \
2524
--to @hcengineering/pod-external \

communication

Submodule communication updated 79 files
99 KB
Binary file not shown.

desktop/src/__test__/main/selfCheckingNode.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@
1414
//
1515

1616
describe('node environment self checking', () => {
17-
test('check Jest\'s node environment', () => {
18-
const isNodeAvailable = typeof process !== 'undefined';
19-
expect(isNodeAvailable).toBe(true);
20-
})
21-
17+
test('check Jest\'s node environment', () => {
18+
const isNodeAvailable = typeof process !== 'undefined'
19+
expect(isNodeAvailable).toBe(true)
20+
})
2221
})
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
//
2+
// Copyright © 2025 Hardcore Engineering Inc.
3+
//
4+
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License. You may
6+
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
//
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
import { Settings } from '../../main/settings'
17+
import { PackedConfig } from '../../main/config'
18+
19+
const createMockStore = (): { get: jest.Mock, set: jest.Mock } => {
20+
const store: Record<string, any> = {}
21+
return {
22+
get: jest.fn((key: string) => store[key]),
23+
set: jest.fn((key: string, value: any) => { store[key] = value })
24+
}
25+
}
26+
27+
jest.mock('electron-store', () => {
28+
return jest.fn()
29+
})
30+
31+
describe('Settings', () => {
32+
let originalEnvironment: NodeJS.ProcessEnv
33+
let stubStoreInstance: ReturnType<typeof createMockStore>
34+
35+
beforeEach(() => {
36+
originalEnvironment = process.env
37+
process.env = { ...originalEnvironment }
38+
stubStoreInstance = createMockStore()
39+
jest.clearAllMocks()
40+
})
41+
42+
afterEach(() => {
43+
process.env = originalEnvironment
44+
jest.clearAllMocks()
45+
})
46+
47+
describe('readServerUrl', () => {
48+
test('isDev is true', () => {
49+
const systemUnderTest = new Settings(stubStoreInstance as any, true)
50+
51+
const actualUrl = systemUnderTest.readServerUrl()
52+
53+
expect(actualUrl).toBe('http://huly.local:8087')
54+
})
55+
56+
test('isDev is true and FRONT_URL is set', () => {
57+
process.env.FRONT_URL = 'http://custom-dev.local:3000'
58+
const systemUnderTest = new Settings(stubStoreInstance as any, true)
59+
60+
const actualUrl = systemUnderTest.readServerUrl()
61+
62+
expect(actualUrl).toBe('http://custom-dev.local:3000')
63+
})
64+
65+
test('isDev is false and server is in store', () => {
66+
const expectedUrl = 'https://stored.server.com'
67+
stubStoreInstance.get.mockReturnValue(expectedUrl)
68+
const systemUnderTest = new Settings(stubStoreInstance as any, false)
69+
70+
const actualUrl = systemUnderTest.readServerUrl()
71+
72+
expect(actualUrl).toBe(expectedUrl)
73+
})
74+
75+
test('store is empty and packed config exists', () => {
76+
stubStoreInstance.get.mockReturnValue(undefined)
77+
const expectedUrl = 'https://packed.server.com'
78+
const packedConfig: PackedConfig = { server: expectedUrl }
79+
const systemUnderTest = new Settings(stubStoreInstance as any, false, packedConfig)
80+
81+
const actualUrl = systemUnderTest.readServerUrl()
82+
83+
expect(actualUrl).toBe(expectedUrl)
84+
})
85+
86+
test('store and packed config are empty', () => {
87+
stubStoreInstance.get.mockReturnValue(undefined)
88+
const expectedUrl = 'https://env.server.com'
89+
process.env.FRONT_URL = expectedUrl
90+
const systemUnderTest = new Settings(stubStoreInstance as any, false)
91+
92+
const actualUrl = systemUnderTest.readServerUrl()
93+
94+
expect(actualUrl).toBe(expectedUrl)
95+
})
96+
97+
test('all options are unavailable', () => {
98+
stubStoreInstance.get.mockReturnValue(undefined)
99+
delete process.env.FRONT_URL
100+
const systemUnderTest = new Settings(stubStoreInstance as any, false)
101+
102+
const result = systemUnderTest.readServerUrl()
103+
104+
expect(result).toBe('https://huly.app')
105+
})
106+
107+
test('all (store, packed config, environment) options are available', () => {
108+
const expectedUrl = 'https://store.priority.com'
109+
stubStoreInstance.get.mockReturnValue(expectedUrl)
110+
process.env.FRONT_URL = 'https://env.server.com'
111+
const packedConfig: PackedConfig = { server: 'https://packed.server.com' }
112+
const systemUnderTest = new Settings(stubStoreInstance as any, false, packedConfig)
113+
114+
const actualUrl = systemUnderTest.readServerUrl()
115+
116+
expect(actualUrl).toBe(expectedUrl)
117+
})
118+
})
119+
120+
describe('read/write', () => {
121+
let systemUnderTest: Settings
122+
beforeEach(() => {
123+
systemUnderTest = new Settings(stubStoreInstance as any, false)
124+
})
125+
126+
describe('isMinimizeToTrayEnabled', () => {
127+
test.each([
128+
{ storedValue: true, expected: true, description: 'stored value is true' },
129+
{ storedValue: false, expected: false, description: 'stored value is false' }
130+
])('$description', ({ storedValue, expected }) => {
131+
stubStoreInstance.get.mockReturnValue(storedValue)
132+
133+
const actualValue = systemUnderTest.isMinimizeToTrayEnabled()
134+
135+
expect(actualValue).toBe(expected)
136+
})
137+
138+
test.each([
139+
{ storedValue: undefined, description: 'no value is stored (undefined)' },
140+
{ storedValue: null, description: 'stored value is null' }
141+
])('$description', ({ storedValue }) => {
142+
stubStoreInstance.get.mockReturnValue(storedValue)
143+
144+
const actualValue = systemUnderTest.isMinimizeToTrayEnabled()
145+
146+
expect(actualValue).toBe(false)
147+
})
148+
})
149+
150+
describe('setMinimizeToTrayEnabled', () => {
151+
test.each([
152+
{ value: true, description: 'stored value is true' },
153+
{ value: false, description: 'stored value is false' }
154+
])('$description', ({ value }) => {
155+
systemUnderTest.setMinimizeToTrayEnabled(value)
156+
157+
expect(systemUnderTest.isMinimizeToTrayEnabled()).toBe(value)
158+
})
159+
})
160+
161+
describe('setServerUrl', () => {
162+
test('write than read', () => {
163+
const expectedUrl = 'https://new.server.com'
164+
165+
systemUnderTest.setServerUrl(expectedUrl)
166+
167+
expect(systemUnderTest.readServerUrl()).toBe(expectedUrl)
168+
})
169+
})
170+
171+
describe('getWindowBounds', () => {
172+
test('read', () => {
173+
const expectedValue = { x: 100, y: 300, width: 500, height: 700 }
174+
stubStoreInstance.get.mockReturnValue(expectedValue)
175+
176+
const actulValue = systemUnderTest.getWindowBounds()
177+
178+
expect(actulValue).toEqual(expectedValue)
179+
})
180+
181+
test('no bounds are stored', () => {
182+
stubStoreInstance.get.mockReturnValue(undefined)
183+
184+
expect(systemUnderTest.getWindowBounds()).toBeUndefined()
185+
})
186+
})
187+
188+
describe('setWindowBounds', () => {
189+
test('write than read', () => {
190+
const expectedValue = { x: 100, y: 200, width: 800, height: 600 }
191+
192+
systemUnderTest.setWindowBounds(expectedValue)
193+
194+
expect(systemUnderTest.getWindowBounds()).toBe(expectedValue)
195+
})
196+
})
197+
})
198+
})
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// Copyright © 2025 Hardcore Engineering Inc.
3+
//
4+
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License. You may
6+
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
//
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
16+
import { getBadgeIconInfo } from '../../main/trayUtils'
17+
18+
describe('getBadgeIconInfo', () => {
19+
const baseTitle = 'Huly'
20+
21+
it('count of 0', () => {
22+
const result = getBadgeIconInfo(0, baseTitle)
23+
expect(result).toEqual({
24+
fileName: '',
25+
tooltip: baseTitle
26+
})
27+
})
28+
29+
it('negative count', () => {
30+
const result = getBadgeIconInfo(-5, baseTitle)
31+
expect(result).toEqual({
32+
fileName: '',
33+
tooltip: baseTitle
34+
})
35+
})
36+
37+
it.each([1, 2, 3, 4, 5, 6, 7, 8, 9])('count of %i', (count: number) => {
38+
const result = getBadgeIconInfo(count, baseTitle)
39+
expect(result).toEqual({
40+
fileName: 'TrayIconWithBadge.ico',
41+
tooltip: `${baseTitle}: ${count} unread`
42+
})
43+
})
44+
45+
describe('badge count 10-98', () => {
46+
const testCases: number[] = []
47+
for (let i = 10; i <= 98; i++) {
48+
testCases.push(i)
49+
}
50+
51+
it.each(testCases)('count of %i', (count: number) => {
52+
const result = getBadgeIconInfo(count, baseTitle)
53+
expect(result).toEqual({
54+
fileName: 'TrayIconWithBadge.ico',
55+
tooltip: `${baseTitle}: ${count} unread`
56+
})
57+
})
58+
})
59+
60+
it.each([99, 100, 200, 301])('count of %i', (count: number) => {
61+
const result = getBadgeIconInfo(count, baseTitle)
62+
expect(result).toEqual({
63+
fileName: 'TrayIconWithBadge.ico',
64+
tooltip: `${baseTitle}: ${count} unread`
65+
})
66+
})
67+
})

desktop/src/main/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
import * as path from 'path'
1616
import * as fs from 'fs'
1717

18-
interface PackedConfig {
18+
export interface PackedConfig {
1919
server?: string
2020
updatesChannelKey?: string
2121
}
2222

23-
const configPath = path.join(process.resourcesPath, 'config/config.json')
23+
const configPath = path.join(process.resourcesPath, 'config', 'config.json')
2424

2525
export function readPackedConfig (): PackedConfig | undefined {
2626
if (fs.existsSync(configPath)) {

desktop/src/main/customMenu.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313
// limitations under the License.
1414
//
1515

16-
import { app, BrowserWindow } from 'electron'
16+
import { BrowserWindow } from 'electron'
1717
import { MenuBarAction, CommandLogout, CommandSelectWorkspace, CommandOpenSettings } from '../ui/types'
18+
import { TrayController } from './tray'
1819

19-
export function dispatchMenuBarAction (mainWindow: BrowserWindow | undefined, action: MenuBarAction): void {
20+
export function dispatchMenuBarAction (mainWindow: BrowserWindow | undefined, action: MenuBarAction, tray: TrayController | undefined): void {
2021
if (mainWindow == null) {
2122
return
2223
}
@@ -42,7 +43,7 @@ export function dispatchMenuBarAction (mainWindow: BrowserWindow | undefined, ac
4243
mainWindow.webContents.send(CommandLogout)
4344
break
4445
case 'exit':
45-
app.quit()
46+
mainWindow.close()
4647
break
4748
case 'undo':
4849
mainWindow.webContents.undo()
@@ -86,6 +87,13 @@ export function dispatchMenuBarAction (mainWindow: BrowserWindow | undefined, ac
8687
case 'toggle-fullscreen':
8788
mainWindow.setFullScreen(!mainWindow.isFullScreen())
8889
break
90+
case 'toggle-minimize-to-tray': {
91+
if (tray != null) {
92+
const newSetting = tray.toggleMinimizeToTray()
93+
mainWindow.webContents.send('minimize-to-tray-setting-changed', newSetting)
94+
}
95+
break
96+
}
8997
default:
9098
console.log('unknown menu action:', action)
9199
}

0 commit comments

Comments
 (0)