Skip to content

Commit 97b7e74

Browse files
authored
Merge pull request #9344 from ever-co/develop
Stage
2 parents 7c1f2e6 + 9e183aa commit 97b7e74

File tree

225 files changed

+7797
-1040
lines changed

Some content is hidden

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

225 files changed

+7797
-1040
lines changed

.cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,8 @@
810810
"Liskov",
811811
"backoff",
812812
"autodrain",
813-
"pluginname"
813+
"pluginname",
814+
"Mobi"
814815
],
815816
"useGitignore": true,
816817
"ignorePaths": [

.deploy/webapp/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ COPY --chown=node:node packages/contracts/package.json ./packages/contracts/
100100
COPY --chown=node:node packages/auth/package.json ./packages/auth/
101101
COPY --chown=node:node packages/core/package.json ./packages/core/
102102
COPY --chown=node:node packages/plugin/package.json ./packages/plugin/
103+
COPY --chown=node:node packages/desktop-ui-lib/package.json ./packages/desktop-ui-lib/
103104
COPY --chown=node:node packages/plugins/integration-ai-ui/package.json ./packages/plugins/integration-ai-ui/
104105
COPY --chown=node:node packages/plugins/integration-ai/package.json ./packages/plugins/integration-ai/
105106
COPY --chown=node:node packages/plugins/integration-hubstaff-ui/package.json ./packages/plugins/integration-hubstaff-ui/

apps/agent/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@
3737
"electronmon": "^2.0.2"
3838
},
3939
"dependencies": {
40-
"@angular/animations": "^19.2.17",
41-
"@angular/cdk": "^19.2.17",
42-
"@angular/common": "^19.2.17",
43-
"@angular/core": "^19.2.17",
44-
"@angular/forms": "^19.2.17",
45-
"@angular/material": "^19.2.17",
46-
"@angular/router": "^19.2.17",
40+
"@angular/animations": "^19.2.18",
41+
"@angular/cdk": "^19.2.18",
42+
"@angular/common": "^19.2.18",
43+
"@angular/core": "^19.2.18",
44+
"@angular/forms": "^19.2.18",
45+
"@angular/material": "^19.2.18",
46+
"@angular/router": "^19.2.18",
4747
"@datorama/akita": "^8.0.1",
4848
"@datorama/akita-ngdevtools": "^7.0.0",
4949
"@electron/remote": "^2.0.8",

apps/agent/src/app/app-routing.module.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,11 @@ const routes: Routes = [
2727
{
2828
path: 'plugins',
2929
canActivate: [AuthConnectionGuard],
30-
loadComponent: () => import('@gauzy/desktop-ui-lib').then((m) => m.PluginLayoutComponent),
31-
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.pluginRoutes)
30+
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.PluginsModule)
3231
},
3332
{
3433
path: 'settings',
35-
component: SettingsComponent,
36-
loadChildren: () => import('@gauzy/desktop-ui-lib').then((m) => m.pluginRoutes)
34+
component: SettingsComponent
3735
},
3836
{
3937
path: 'updater',

apps/agent/src/app/app.module.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {
2525
NgxLoginModule,
2626
NoAuthGuard,
2727
OrganizationInterceptor,
28-
PluginsModule,
2928
RefreshTokenInterceptor,
3029
ScreenCaptureModule,
3130
ServerConnectionService,
@@ -120,8 +119,7 @@ if (environment.SENTRY_DSN) {
120119
NbDatepickerModule.forRoot(),
121120
AboutModule,
122121
AgentDashboardModule,
123-
AlwaysOnModule,
124-
PluginsModule
122+
AlwaysOnModule
125123
],
126124
providers: [
127125
AppService,

apps/agent/src/constant.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ const MAIN_EVENT_TYPE = {
1414
INIT_SCREENSHOT: 'INIT_SCREENSHOT',
1515
START_TIMER_API: 'START_TIMER_API',
1616
CHECK_STATUS_TIMER: 'CHECK_STATUS_TIMER',
17-
TRAY_TIMER_STATUS: 'TRAY_TIMER_STATUS'
17+
TRAY_TIMER_STATUS: 'TRAY_TIMER_STATUS',
18+
ACTIVITY_PAUSED: 'ACTIVITY_PAUSED',
19+
ACTIVITY_RESUME: 'ACTIVITY_RESUME',
20+
EXIT_APP: 'EXIT_APP',
21+
STOP_N_EXIT: 'STOP_N_EXIT'
1822
}
1923

2024
export type TMainEventType = typeof MAIN_EVENT_TYPE[keyof typeof MAIN_EVENT_TYPE];

apps/agent/src/index.ts

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@ import { BrowserWindow, shell, app, ipcMain } from 'electron';
55
import * as path from 'path';
66
import { InitApplication } from './main/init';
77
import {
8-
AppError,
9-
DesktopUpdater,
108
LocalStore,
119
} from '@gauzy/desktop-lib';
12-
import PullActivities from './main/workers/pull-activities';
13-
import PushActivities from './main/workers/push-activities';
14-
import { getAuthConfig } from './main/util';
1510

1611
let popupWin: BrowserWindow | null = null;
1712

@@ -21,14 +16,8 @@ log.info(`Sqlite DB path: ${sqlite3filename}`);
2116
const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']);
2217

2318
const args = process.argv.slice(1);
24-
const updater = new DesktopUpdater({
25-
repository: process.env.REPO_NAME,
26-
owner: process.env.REPO_OWNER,
27-
typeRelease: 'releases'
28-
});
2919
args.some((val) => val === '--serve');
3020

31-
3221
LocalStore.setFilePath({
3322
iconPath: path.join(__dirname, 'assets', 'icons', 'menu', 'icon.png')
3423
});
@@ -44,30 +33,7 @@ app.commandLine.appendSwitch('disable-http2');
4433

4534
ipcMain.on('quit', quit);
4635

47-
async function stopAppActivity() {
48-
const auth = getAuthConfig();
49-
const pullActivities = PullActivities.getInstance();
50-
pullActivities.updateAppUserAuth({
51-
tenantId: auth?.user?.employee?.tenantId,
52-
organizationId: auth?.user?.employee?.organizationId,
53-
remoteId: auth?.user?.id
54-
});
55-
await pullActivities.stopTracking();
56-
const pushActivities = PushActivities.getInstance();
57-
await pushActivities.stopPooling();
58-
}
59-
60-
app.on('before-quit', async (e) => {
61-
e.preventDefault();
62-
try {
63-
await stopAppActivity();
64-
updater.cancel();
65-
} catch (e) {
66-
log.error(`ERROR: Occurred while cancel update: ${e}`);
67-
throw new AppError('MAINUPDTABORT', e);
68-
}
69-
app.exit(0);
70-
});
36+
// Removed: before-quit handler now managed by EventHandler.exitApp()
7137

7238
// On OS X it is common for applications and their menu bar
7339
// to stay active until the user quits explicitly with Cmd + Q

apps/agent/src/main/api.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { TimeLogSourceEnum, TimeLogType } from '@gauzy/desktop-activity';
88
import MainEvent from './events/events';
99
import { MAIN_EVENT, MAIN_EVENT_TYPE } from '../constant';
1010
import { TaskStatusEnum, IBaseTaskProperties, ITaskStatus, IPagination } from '@gauzy/contracts';
11+
import { AgentLogger } from './agent-logger';
1112

1213
export interface ITimerResponse {
1314
deletedAt: any
@@ -157,9 +158,11 @@ export class ApiService {
157158
private mainEvent: MainEvent;
158159
private isLogout: boolean;
159160
private statusProgress: ITaskStatus;
161+
private agentLogger: AgentLogger;
160162

161163
constructor() {
162164
this.mainEvent = MainEvent.getInstance();
165+
this.agentLogger = AgentLogger.getInstance();
163166
}
164167

165168
get auth(): Partial<TAuthConfig> {
@@ -261,7 +264,8 @@ export class ApiService {
261264
logType: TimeLogType.TRACKED,
262265
source: TimeLogSourceEnum.DESKTOP,
263266
tenantId: payload.tenantId,
264-
organizationId: payload.organizationId
267+
organizationId: payload.organizationId,
268+
employeeId: payload.employeeId
265269
}
266270
return this.put(path, timeLogPayload);
267271
}
@@ -443,7 +447,7 @@ export class ApiService {
443447

444448
try {
445449
console.log('url', url);
446-
console.log('options data', JSON.stringify(requestOptions));
450+
// console.log('options data', JSON.stringify(requestOptions));
447451
const response = await fetch(url, requestOptions);
448452
console.log(`API ${options.method} ${path}: ${response.status} ${response.statusText}`);
449453
if (!response.ok) {
@@ -467,6 +471,7 @@ export class ApiService {
467471
const respJson = await response.json();
468472
return respJson;
469473
} catch (err) {
474+
this.agentLogger.error(`Error API call, ${err.message}`);
470475
console.error('[Network Error]', err);
471476
const enhancedError = err instanceof Error ? err : new Error(String(err));
472477
enhancedError['url'] = url;

apps/agent/src/main/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ async function handleCloseAuthWindow(appWindow: AppWindow) {
4848
const authConfig = getAuthConfig();
4949
if (!authConfig?.token) {
5050
const DIALOG_TITLE = TranslateService.instant('TIMER_TRACKER.DIALOG.WARNING');
51-
const DIALOG_MESSAGE = TranslateService.instant('TIMER_TRACKER.DIALOG.EXIT_AGENT_CONFIRM');
51+
const DIALOG_MESSAGE = TranslateService.instant('TIMER_TRACKER.DIALOG.EXIT_AGENT_LOGIN_CONFIRM');
5252

5353
const dialog = new DesktopDialog(DIALOG_TITLE, DIALOG_MESSAGE, appWindow.authWindow.browserWindow);
5454
dialog.options.buttons = [

apps/agent/src/main/events/event-handler.ts

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { app } from 'electron';
12
import { MAIN_EVENT, MAIN_EVENT_TYPE } from '../../constant';
23
import PullActivities from '../workers/pull-activities';
34
import PushActivities from '../workers/push-activities';
@@ -6,7 +7,21 @@ import MainEvent from './events';
67
import * as path from 'node:path';
78
import { TrayNotify } from './tray-notify';
89
import { TEventArgs } from './event-types';
9-
import { getAuthConfig, delaySync, TAuthConfig, updateAgentSetting, getAppSetting } from '../util';
10+
import {
11+
getAuthConfig,
12+
delaySync,
13+
TAuthConfig,
14+
updateAgentSetting,
15+
getAppSetting,
16+
getInitialConfig
17+
} from '../util';
18+
import {
19+
DesktopUpdater,
20+
AppError,
21+
TranslateService,
22+
DesktopDialog
23+
} from '@gauzy/desktop-lib';
24+
import { logger as log } from '@gauzy/desktop-core';
1025

1126
const appRootPath: string = path.join(__dirname, '../..');
1227

@@ -17,11 +32,17 @@ export default class EventHandler {
1732
private trayNotify: TrayNotify;
1833
private pullActivities: PullActivities;
1934
private pushActivities: PushActivities;
35+
private updater: DesktopUpdater;
2036

2137
constructor() {
2238
this.mainEvent = MainEvent.getInstance();
2339
this.appWindow = AppWindow.getInstance(appRootPath);
2440
this.trayNotify = TrayNotify.getInstance();
41+
this.updater = new DesktopUpdater({
42+
repository: process.env.REPO_NAME,
43+
owner: process.env.REPO_OWNER,
44+
typeRelease: 'releases'
45+
});
2546
}
2647

2748
static getInstance() {
@@ -132,6 +153,75 @@ export default class EventHandler {
132153
}
133154
}
134155

156+
private async resumeActivity() {
157+
const authConfig = getAuthConfig();
158+
this.getPullActivities(authConfig);
159+
await this.pullActivities.recordIdleTime();
160+
this.pullActivities.startedPausedDate = null;
161+
await this.pullActivities.startTracking(this.pullActivities.isPaused);
162+
this.pullActivities.isPaused = false;
163+
}
164+
165+
private async pauseActivity() {
166+
const authConfig = getAuthConfig();
167+
this.getPullActivities(authConfig);
168+
const isTimeRunning = this.pullActivities.running;
169+
await this.pullActivities.stopTracking(true);
170+
if (isTimeRunning) {
171+
this.pullActivities.startedPausedDate = new Date();
172+
this.pullActivities.isPaused = true;
173+
}
174+
}
175+
176+
async stopAppActivity() {
177+
const authConfig = getAuthConfig();
178+
this.getPullActivities(authConfig);
179+
this.getPushActivities();
180+
if (!authConfig?.token) {
181+
await this.pushActivities.stopPooling();
182+
return;
183+
}
184+
185+
if (this.pullActivities.running) {
186+
await this.pullActivities.stopTracking();
187+
}
188+
await this.pushActivities.stopPooling();
189+
190+
}
191+
192+
async exitDialog() {
193+
const DIALOG_TITLE = TranslateService.instant('TIMER_TRACKER.DIALOG.WARNING');
194+
const DIALOG_MESSAGE = TranslateService.instant('TIMER_TRACKER.DIALOG.EXIT_AGENT_PREVENT_CONFIRM');
195+
const dialog = new DesktopDialog(DIALOG_TITLE, DIALOG_MESSAGE);
196+
dialog.options.buttons = [
197+
TranslateService.instant('OK'),
198+
];
199+
await dialog.show();
200+
}
201+
202+
private async exitApp() {
203+
try {
204+
const appSetting = getAppSetting();
205+
const appConfig = getInitialConfig();
206+
const authConfig = getAuthConfig();
207+
if (appSetting?.allowAgentAppExit || !appConfig?.isSetup || !authConfig?.token) {
208+
await this.stopAppActivity();
209+
this.updater.cancel();
210+
app.quit();
211+
} else {
212+
await this.exitDialog();
213+
}
214+
} catch (e) {
215+
log.error(`ERROR: Failed to exit app: ${e}`);
216+
throw new AppError('MAINUPDTABORT', e);
217+
}
218+
}
219+
220+
private async stopAndExit() {
221+
await this.stopAppTracking();
222+
app.quit();
223+
}
224+
135225
async handleEvent(args: TEventArgs) {
136226
switch (args.type) {
137227
case MAIN_EVENT_TYPE.LOGOUT_EVENT:
@@ -157,6 +247,14 @@ export default class EventHandler {
157247
return this.checkStatusTimer();
158248
case MAIN_EVENT_TYPE.TRAY_TIMER_STATUS:
159249
return this.trayTimerStatus();
250+
case MAIN_EVENT_TYPE.ACTIVITY_RESUME:
251+
return this.resumeActivity();
252+
case MAIN_EVENT_TYPE.ACTIVITY_PAUSED:
253+
return this.pauseActivity();
254+
case MAIN_EVENT_TYPE.EXIT_APP:
255+
return this.exitApp();
256+
case MAIN_EVENT_TYPE.STOP_N_EXIT:
257+
return this.stopAndExit();
160258
default: break;
161259
}
162260
}

0 commit comments

Comments
 (0)