Skip to content

Commit 48d4a37

Browse files
vicky16898SoulKa
authored andcommitted
#158 - save draft request on close
1 parent 5f3c1ba commit 48d4a37

File tree

4 files changed

+72
-31
lines changed

4 files changed

+72
-31
lines changed

src/main/main.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { app, BrowserWindow, shell } from 'electron';
1+
import { app, BrowserWindow, ipcMain, shell } from 'electron';
22
import { EnvironmentService } from 'main/environment/service/environment-service';
33
import 'main/event/main-event-service';
44
import path from 'node:path';
@@ -33,6 +33,30 @@ const createWindow = async () => {
3333
return { action: 'deny' };
3434
});
3535

36+
// Handle window close event
37+
let isClosing = false;
38+
mainWindow.on('close', async (event) => {
39+
if (!isClosing) {
40+
isClosing = true;
41+
event.preventDefault();
42+
mainWindow?.webContents.send('before-close');
43+
44+
// Wait for the renderer to respond or timeout
45+
try {
46+
await new Promise<void>((resolve, reject) => {
47+
ipcMain.once('ready-to-close', () => resolve());
48+
setTimeout(() => reject(new Error('Timeout')), 30000);
49+
});
50+
} catch (error) {
51+
console.error('Could not handle close event in renderer:', error);
52+
}
53+
54+
// Close app
55+
mainWindow.close();
56+
app.quit();
57+
}
58+
});
59+
3660
// Load the index.html of the app.
3761
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
3862
await mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);

src/main/persistence/service/persistence-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ export class PersistenceService {
305305

306306
private async loadRequest(parentId: string, dirPath: string): Promise<TrufosRequest> {
307307
const type = 'request' as const;
308-
const draft = !(await exists(path.join(dirPath, type + '.json')));
308+
const draft = await exists(path.join(dirPath, '~' + type + '.json'));
309309
const info = await this.readInfoFile(dirPath, type, draft);
310310
this.idToPathMap.set(info.id, dirPath);
311311

Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
import { IEventService } from 'shim/event-service';
22
import { MainProcessError } from '@/error/MainProcessError';
33

4-
const METHOD_NAMES = new Set<keyof IEventService>([
5-
'saveRequest',
6-
'sendRequest',
7-
'getAppVersion',
8-
'loadCollection',
9-
'saveChanges',
10-
'discardChanges',
11-
'deleteObject',
12-
'getActiveEnvironmentVariables',
13-
'getVariable',
14-
'setCollectionVariables',
15-
]);
16-
17-
const INSTANCE = {} as IEventService;
18-
for (const methodName of METHOD_NAMES) {
19-
Reflect.defineProperty(INSTANCE, methodName, {
20-
value: createEventMethod(methodName),
21-
writable: false,
22-
enumerable: true,
23-
configurable: false,
24-
});
25-
}
26-
274
/**
285
* Creates a method that sends an IPC event to the main process and returns the result. If the
296
* result is an error, it is thrown.
307
* @param methodName The name of the event method to call in the main process.
318
*/
32-
function createEventMethod(methodName: keyof IEventService) {
33-
return async function (...args: any[]) {
9+
function createEventMethod<T extends keyof IEventService>(methodName: T) {
10+
return async function (
11+
...args: Parameters<IEventService[T]>
12+
): Promise<
13+
ReturnType<IEventService[T]> extends Promise<infer R> ? R : ReturnType<IEventService[T]>
14+
> {
3415
const result = await window.electron.ipcRenderer.invoke(methodName, ...args);
3516
if (result instanceof Error) {
3617
throw new MainProcessError(result.message);
@@ -40,7 +21,33 @@ function createEventMethod(methodName: keyof IEventService) {
4021
};
4122
}
4223

43-
export const RendererEventService = {
44-
/** The singleton instance of the RendererEventService */
45-
instance: INSTANCE,
46-
};
24+
export interface RendererEventService {
25+
on(event: 'before-close', listener: () => void): this;
26+
27+
emit(event: 'ready-to-close'): this;
28+
}
29+
30+
export class RendererEventService implements IEventService {
31+
public static readonly instance = new RendererEventService();
32+
33+
on(event: string, listener: (...args: unknown[]) => void) {
34+
window.electron.ipcRenderer.on(event, listener);
35+
return this;
36+
}
37+
38+
emit(event: string, ...args: unknown[]) {
39+
window.electron.ipcRenderer.send(event, ...args);
40+
return this;
41+
}
42+
43+
saveRequest = createEventMethod('saveRequest');
44+
sendRequest = createEventMethod('sendRequest');
45+
getAppVersion = createEventMethod('getAppVersion');
46+
loadCollection = createEventMethod('loadCollection');
47+
saveChanges = createEventMethod('saveChanges');
48+
discardChanges = createEventMethod('discardChanges');
49+
deleteObject = createEventMethod('deleteObject');
50+
getActiveEnvironmentVariables = createEventMethod('getActiveEnvironmentVariables');
51+
getVariable = createEventMethod('getVariable');
52+
setCollectionVariables = createEventMethod('setCollectionVariables');
53+
}

src/renderer/state/requestStore.ts

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ import { RendererEventService } from '@/services/event/renderer-event-service';
88
import { useActions } from '@/state/util';
99

1010
const eventService = RendererEventService.instance;
11+
eventService.on('before-close', async () => {
12+
console.info('Saving currently opened request before closing');
13+
const state = useRequestStore.getState();
14+
const request = selectRequest(state);
15+
if (request != null && request.draft) {
16+
console.debug(`Saving request with ID ${request.id}`);
17+
await eventService.saveRequest(request, state.requestEditor?.getValue());
18+
}
19+
eventService.emit('ready-to-close');
20+
});
1121

1222
interface RequestState {
1323
requests: TrufosRequest[];

0 commit comments

Comments
 (0)