Skip to content

Commit e68b285

Browse files
authored
Feat: Enhance import process (#2728)
* add new import dialog for importing non-.opossum files into OpossumUI * accessible through new menu item with submenus for all supported file types * dialog allows selecting input and output file path through native file system dialogs * paths are validated when user clicks the import button, error messages are displayed in case validation fails * clicking import button triggers file conversion and loading, loading log is displayed directly in import dialog * open file action now only allows selection of .opossum files
1 parent d3b8a2d commit e68b285

Some content is hidden

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

47 files changed

+1050
-790
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,5 @@ yarn-error.log*
4747
/.run
4848

4949
.env
50+
51+
.gitconfig

public/assets/icons/import-black.png

516 Bytes
Loading

public/assets/icons/import-white.png

724 Bytes
Loading

src/ElectronBackend/errorHandling/__tests__/errorHandling.test.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { AllowedFrontendChannels } from '../../../shared/ipc-channels';
99
import { SendErrorInformationArgs } from '../../../shared/shared-types';
1010
import { loadInputAndOutputFromFilePath } from '../../input/importFromFile';
1111
import {
12-
createListenerCallbackWithErrorHandling,
12+
createVoidListenerCallbackWithErrorHandling,
1313
getMessageBoxContentForErrorsWrapper,
1414
getMessageBoxForErrors,
1515
} from '../errorHandling';
@@ -46,7 +46,7 @@ describe('error handling', () => {
4646
arg2: true,
4747
};
4848

49-
await createListenerCallbackWithErrorHandling(
49+
await createVoidListenerCallbackWithErrorHandling(
5050
mainWindow,
5151
testFunction,
5252
)(testArgs);
@@ -65,7 +65,10 @@ describe('error handling', () => {
6565
throw new Error('TEST_ERROR');
6666
}
6767

68-
await createListenerCallbackWithErrorHandling(mainWindow, testFunction)();
68+
await createVoidListenerCallbackWithErrorHandling(
69+
mainWindow,
70+
testFunction,
71+
)();
6972

7073
expect(dialog.showMessageBox).toHaveBeenCalledWith(
7174
expect.objectContaining({

src/ElectronBackend/errorHandling/errorHandling.ts

+53-22
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,63 @@ import { getGlobalBackendState } from '../main/globalBackendState';
1717
import logger from '../main/logger';
1818
import { getLoadedFilePath } from '../utils/getLoadedFile';
1919

20-
export function createListenerCallbackWithErrorHandling(
20+
async function reportListenerError(
2121
mainWindow: BrowserWindow,
22-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
23-
func: Function,
24-
): (...args: Array<unknown>) => Promise<void> {
25-
return async (...args: Array<unknown>): Promise<void> => {
22+
error: unknown,
23+
): Promise<void> {
24+
if (error instanceof Error) {
25+
logger.info(`Failed executing callback function: ${error.message}`);
26+
await getMessageBoxForErrors(
27+
error.message,
28+
error.stack ?? '',
29+
mainWindow,
30+
true,
31+
);
32+
} else {
33+
logger.info('Failed executing callback function.');
34+
await getMessageBoxForErrors(
35+
'Unexpected internal error',
36+
'',
37+
mainWindow,
38+
true,
39+
);
40+
}
41+
}
42+
43+
type FuncType<T> = T extends (...args: infer P) => infer R
44+
? (...args: P) => R
45+
: never;
46+
47+
type RemovePromise<A> = A extends Promise<infer B> ? B : A;
48+
type ReturnTypeWithoutPromise<A> =
49+
A extends FuncType<A> ? RemovePromise<ReturnType<A>> : never;
50+
type FTParameters<A> = A extends FuncType<A> ? Parameters<A> : never;
51+
52+
export function createVoidListenerCallbackWithErrorHandling<F>(
53+
mainWindow: BrowserWindow,
54+
func: F & FuncType<F>,
55+
): (...args: FTParameters<F>) => Promise<void> {
56+
return async (...args: FTParameters<F>): Promise<void> => {
2657
try {
2758
await func(...args);
2859
} catch (error: unknown) {
29-
if (error instanceof Error) {
30-
logger.info(`Failed executing callback function: ${error.message}`);
31-
await getMessageBoxForErrors(
32-
error.message,
33-
error.stack ?? '',
34-
mainWindow,
35-
true,
36-
);
37-
} else {
38-
logger.info('Failed executing callback function.');
39-
await getMessageBoxForErrors(
40-
'Unexpected internal error',
41-
'',
42-
mainWindow,
43-
true,
44-
);
45-
}
60+
await reportListenerError(mainWindow, error);
61+
}
62+
};
63+
}
64+
65+
export function createListenerCallbackWithErrorHandling<F>(
66+
mainWindow: BrowserWindow,
67+
func: F & FuncType<F>,
68+
): (...args: FTParameters<F>) => Promise<ReturnTypeWithoutPromise<F> | null> {
69+
return async (
70+
...args: FTParameters<F>
71+
): Promise<ReturnTypeWithoutPromise<F> | null> => {
72+
try {
73+
return (await func(...args)) as ReturnTypeWithoutPromise<F>;
74+
} catch (error: unknown) {
75+
await reportListenerError(mainWindow, error);
76+
return Promise.resolve(null);
4677
}
4778
};
4879
}

0 commit comments

Comments
 (0)