Skip to content

Commit dafca7b

Browse files
authored
Merge pull request #2799 from opossum-tool/feat/merge-app
Merging input files (App)
2 parents bff2ccb + d5647b8 commit dafca7b

Some content is hidden

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

43 files changed

+826
-243
lines changed

public/assets/icons/merge-black.png

190 Bytes
Loading

public/assets/icons/merge-white.png

208 Bytes
Loading

src/ElectronBackend/main/__tests__/listeners.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ import { setGlobalBackendState } from '../globalBackendState';
2929
import {
3030
exportFileListener,
3131
importFileListener,
32-
importFileSelectInputListener,
3332
importFileSelectSaveLocationListener,
3433
linkHasHttpSchema,
3534
openLinkListener,
3635
selectBaseURLListener,
36+
selectFileListener,
3737
} from '../listeners';
3838
import { importFileFormats } from '../menu/fileMenu';
3939

@@ -412,7 +412,7 @@ describe('getImportFileListener', () => {
412412
listener();
413413

414414
expect(mainWindow.webContents.send).toHaveBeenCalledWith(
415-
AllowedFrontendChannels.ImportFileShowDialog,
415+
AllowedFrontendChannels.ShowImportDialog,
416416
fileFormat,
417417
);
418418
});
@@ -424,7 +424,7 @@ describe('getImportFileSelectInputListener', () => {
424424
const fileFormat = importFileFormats[0];
425425
const selectedFilePath = '/home/input.json';
426426

427-
const listener = importFileSelectInputListener(mainWindow);
427+
const listener = selectFileListener(mainWindow);
428428

429429
jest.mocked(openNonOpossumFileDialog).mockReturnValue([selectedFilePath]);
430430

@@ -440,7 +440,7 @@ describe('getImportFileSelectInputListener', () => {
440440
const mainWindow = await initWindowAndBackendState();
441441
const fileFormat = importFileFormats[0];
442442

443-
const listener = importFileSelectInputListener(mainWindow);
443+
const listener = selectFileListener(mainWindow);
444444

445445
jest
446446
.mocked(openNonOpossumFileDialog)

src/ElectronBackend/main/dialogs.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function openNonOpossumFileDialog(
3232
): Array<string> | undefined {
3333
return openFileDialog([
3434
{
35-
name: `${fileFormat.name}s (${fileFormat.extensions.map((ext) => `.${ext}`).join('/')})`,
35+
name: `${fileFormat.name} Files (${fileFormat.extensions.map((ext) => `.${ext}`).join('/')})`,
3636
extensions: fileFormat.extensions,
3737
},
3838
]);

src/ElectronBackend/main/listeners.ts

+84-7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
PackageInfo,
2525
SaveFileArgs,
2626
} from '../../shared/shared-types';
27+
import { text } from '../../shared/text';
2728
import { writeFile, writeOpossumFile } from '../../shared/write-file';
2829
import { LoadedFileFormat } from '../enums/enums';
2930
import {
@@ -32,7 +33,10 @@ import {
3233
} from '../errorHandling/errorHandling';
3334
import { loadInputAndOutputFromFilePath } from '../input/importFromFile';
3435
import { serializeAttributions } from '../input/parseInputData';
35-
import { convertToOpossum } from '../opossum-file/opossum-file';
36+
import {
37+
convertToOpossum,
38+
mergeFileIntoOpossum,
39+
} from '../opossum-file/opossum-file';
3640
import { writeCsvToFile } from '../output/writeCsvToFile';
3741
import { writeSpdxFile } from '../output/writeSpdxFile';
3842
import { GlobalBackendState, OpossumOutputFile } from '../types/types';
@@ -132,12 +136,20 @@ export async function handleOpeningFile(
132136
export const importFileListener =
133137
(mainWindow: BrowserWindow, fileFormat: FileFormatInfo) => (): void => {
134138
mainWindow.webContents.send(
135-
AllowedFrontendChannels.ImportFileShowDialog,
139+
AllowedFrontendChannels.ShowImportDialog,
140+
fileFormat,
141+
);
142+
};
143+
144+
export const getMergeListener =
145+
(mainWindow: BrowserWindow, fileFormat: FileFormatInfo) => (): void => {
146+
mainWindow.webContents.send(
147+
AllowedFrontendChannels.ShowMergeDialog,
136148
fileFormat,
137149
);
138150
};
139151

140-
export const importFileSelectInputListener =
152+
export const selectFileListener =
141153
(mainWindow: BrowserWindow) =>
142154
async (
143155
_: Electron.IpcMainInvokeEvent,
@@ -183,19 +195,31 @@ export const importFileConvertAndLoadListener =
183195

184196
try {
185197
if (!resourceFilePath.trim() || !fs.existsSync(resourceFilePath)) {
186-
throw new Error('Input file does not exist');
198+
throw new Error(text.backendError.inputFileDoesNotExist);
199+
}
200+
201+
try {
202+
fs.accessSync(resourceFilePath, fs.constants.R_OK);
203+
} catch (error) {
204+
throw new Error(text.backendError.inputFilePermissionError);
187205
}
188206

189207
if (!opossumFilePath.trim()) {
190-
throw new Error('No .opossum save location selected');
208+
throw new Error(text.backendError.opossumFileNotSelected);
191209
}
192210

193211
if (!opossumFilePath.endsWith('.opossum')) {
194-
throw new Error('Output file name must have .opossum extension');
212+
throw new Error(text.backendError.opossumFileWrongExtension);
195213
}
196214

197215
if (!fs.existsSync(path.dirname(opossumFilePath))) {
198-
throw new Error('Output directory does not exist');
216+
throw new Error(text.backendError.opossumFileDirectoryDoesNotExist);
217+
}
218+
219+
try {
220+
fs.accessSync(path.dirname(opossumFilePath), fs.constants.W_OK);
221+
} catch (error) {
222+
throw new Error(text.backendError.opossumFilePermissionError);
199223
}
200224

201225
logger.info('Converting input file to .opossum format');
@@ -215,6 +239,59 @@ export const importFileConvertAndLoadListener =
215239
}
216240
};
217241

242+
export const mergeFileAndLoadListener =
243+
(mainWindow: BrowserWindow) =>
244+
async (
245+
_: Electron.IpcMainInvokeEvent,
246+
inputFilePath: string,
247+
fileType: FileType,
248+
): Promise<boolean> => {
249+
setLoadingState(mainWindow.webContents, true);
250+
251+
try {
252+
if (!inputFilePath.trim() || !fs.existsSync(inputFilePath)) {
253+
throw new Error(text.backendError.inputFileDoesNotExist);
254+
}
255+
256+
try {
257+
fs.accessSync(inputFilePath, fs.constants.R_OK);
258+
} catch (error) {
259+
throw new Error(text.backendError.inputFilePermissionError);
260+
}
261+
262+
const currentOpossumFilePath = getGlobalBackendState().opossumFilePath;
263+
264+
if (!currentOpossumFilePath) {
265+
throw new Error(text.backendError.noOpenFileToMergeInto);
266+
}
267+
268+
try {
269+
fs.copyFileSync(
270+
currentOpossumFilePath,
271+
`${currentOpossumFilePath}.backup`,
272+
);
273+
} catch (error) {
274+
throw new Error(text.backendError.cantCreateBackup);
275+
}
276+
277+
logger.info('Merging input file into current .opossum file');
278+
await mergeFileIntoOpossum(
279+
inputFilePath,
280+
currentOpossumFilePath,
281+
fileType,
282+
);
283+
284+
await openFile(mainWindow, currentOpossumFilePath, () => {});
285+
286+
return true;
287+
} catch (error) {
288+
sendListenerErrorToFrontend(mainWindow, error);
289+
return false;
290+
} finally {
291+
setLoadingState(mainWindow.webContents, false);
292+
}
293+
};
294+
218295
function initializeGlobalBackendState(
219296
filePath: string,
220297
isOpossumFormat: boolean,

src/ElectronBackend/main/main.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import { createWindow } from './createWindow';
1111
import {
1212
exportFileListener,
1313
importFileConvertAndLoadListener,
14-
importFileSelectInputListener,
1514
importFileSelectSaveLocationListener,
15+
mergeFileAndLoadListener,
1616
openFileListener,
1717
openLinkListener,
1818
saveFileListener,
19+
selectFileListener,
1920
} from './listeners';
2021
import { createMenu } from './menu';
21-
import { activateMenuItems } from './menu/initiallyDisabledMenuItems';
22+
import { DisabledMenuItemHandler } from './menu/DisabledMenuItemHandler';
2223
import { openFileFromCliOrEnvVariableIfProvided } from './openFileFromCliOrEnvVariableIfProvided';
2324
import { UserSettings } from './user-settings';
2425

@@ -65,19 +66,23 @@ export async function main(): Promise<void> {
6566
});
6667
ipcMain.handle(
6768
IpcChannel.OpenFile,
68-
openFileListener(mainWindow, activateMenuItems),
69-
);
70-
ipcMain.handle(
71-
IpcChannel.ImportFileSelectInput,
72-
importFileSelectInputListener(mainWindow),
69+
openFileListener(mainWindow, DisabledMenuItemHandler.activateMenuItems),
7370
);
71+
ipcMain.handle(IpcChannel.SelectFile, selectFileListener(mainWindow));
7472
ipcMain.handle(
7573
IpcChannel.ImportFileSelectSaveLocation,
7674
importFileSelectSaveLocationListener(mainWindow),
7775
);
7876
ipcMain.handle(
7977
IpcChannel.ImportFileConvertAndLoad,
80-
importFileConvertAndLoadListener(mainWindow, activateMenuItems),
78+
importFileConvertAndLoadListener(
79+
mainWindow,
80+
DisabledMenuItemHandler.activateMenuItems,
81+
),
82+
);
83+
ipcMain.handle(
84+
IpcChannel.MergeFileAndLoad,
85+
mergeFileAndLoadListener(mainWindow),
8186
);
8287
ipcMain.handle(IpcChannel.SaveFile, saveFileListener(mainWindow));
8388
ipcMain.handle(IpcChannel.ExportFile, exportFileListener(mainWindow));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
2+
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
import { Menu } from 'electron';
6+
7+
export class DisabledMenuItemHandler {
8+
private static nextId: number = 0;
9+
10+
static registerDisabledMenuItem(): string {
11+
const idString = DisabledMenuItemHandler.nextId.toString();
12+
DisabledMenuItemHandler.nextId++;
13+
return idString;
14+
}
15+
16+
private static disabledIds(): Array<string> {
17+
return Array(DisabledMenuItemHandler.nextId)
18+
.keys()
19+
.map((id) => id.toString())
20+
.toArray();
21+
}
22+
23+
static activateMenuItems(): void {
24+
const menu = Menu.getApplicationMenu();
25+
DisabledMenuItemHandler.disabledIds().forEach((id) => {
26+
const menuItem = menu?.getMenuItemById(id);
27+
if (menuItem) {
28+
menuItem.enabled = true;
29+
}
30+
});
31+
}
32+
}

src/ElectronBackend/main/menu/aboutMenu.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// SPDX-License-Identifier: Apache-2.0
66
import { shell } from 'electron';
77

8+
import { text } from '../../../shared/text';
89
import { getIconBasedOnTheme } from '../iconHelpers';
910
import {
1011
getPathOfChromiumNoticeDocument,
@@ -17,7 +18,7 @@ function getOpenOnGithub() {
1718
'icons/github-white.png',
1819
'icons/github-black.png',
1920
),
20-
label: 'Open on GitHub',
21+
label: text.menu.aboutSubmenu.openOnGithub,
2122
click: () =>
2223
shell.openExternal('https://github.com/opossum-tool/opossumUI'),
2324
};
@@ -29,7 +30,7 @@ function getOpossumUiNotices() {
2930
'icons/notice-white.png',
3031
'icons/notice-black.png',
3132
),
32-
label: 'OpossumUI Notices',
33+
label: text.menu.aboutSubmenu.opossumUINotices,
3334
click: () => shell.openPath(getPathOfNoticeDocument()),
3435
};
3536
}
@@ -40,14 +41,14 @@ function getChromiumNotices() {
4041
'icons/chromium-white.png',
4142
'icons/chromium-black.png',
4243
),
43-
label: 'Chromium Notices',
44+
label: text.menu.aboutSubmenu.chromiumNotices,
4445
click: () => shell.openPath(getPathOfChromiumNoticeDocument()),
4546
};
4647
}
4748

4849
export function getAboutMenu() {
4950
return {
50-
label: 'About',
51+
label: text.menu.about,
5152
submenu: [getOpenOnGithub(), getOpossumUiNotices(), getChromiumNotices()],
5253
};
5354
}

0 commit comments

Comments
 (0)