Skip to content

Commit 7145e7d

Browse files
authored
Merge pull request #2815 from opossum-tool/refactor/unify-loading-state
Unify handling of loading state
2 parents 09512d5 + 7c23e99 commit 7145e7d

File tree

18 files changed

+102
-151
lines changed

18 files changed

+102
-151
lines changed

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

-35
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
//
55
// SPDX-License-Identifier: Apache-2.0
66
import { BrowserWindow, dialog, shell, WebContents } from 'electron';
7-
import fs from 'fs';
87

98
import {
109
AllowedFrontendChannels,
@@ -16,10 +15,8 @@ import {
1615
ExportSpdxDocumentYamlArgs,
1716
ExportType,
1817
} from '../../../shared/shared-types';
19-
import { writeFile } from '../../../shared/write-file';
2018
import { faker } from '../../../testing/Faker';
2119
import * as errorHandling from '../../errorHandling/errorHandling';
22-
import { loadInputAndOutputFromFilePath } from '../../input/importFromFile';
2320
import { writeCsvToFile } from '../../output/writeCsvToFile';
2421
import { writeSpdxFile } from '../../output/writeSpdxFile';
2522
import { createWindow } from '../createWindow';
@@ -30,7 +27,6 @@ import {
3027
} from '../dialogs';
3128
import { setGlobalBackendState } from '../globalBackendState';
3229
import {
33-
deleteAndCreateNewAttributionFileListener,
3430
exportFileListener,
3531
importFileListener,
3632
importFileSelectInputListener,
@@ -108,37 +104,6 @@ jest.mock('../dialogs', () => ({
108104
selectBaseURLDialog: jest.fn(),
109105
}));
110106

111-
describe('getDeleteAndCreateNewAttributionFileListener', () => {
112-
it('deletes attribution file and calls loadInputAndOutputFromFilePath', async () => {
113-
const mainWindow = {
114-
webContents: {
115-
send: jest.fn(),
116-
},
117-
setTitle: jest.fn(),
118-
} as unknown as BrowserWindow;
119-
120-
const fileName = faker.string.uuid();
121-
const resourceFilePath = `${fileName}.json`;
122-
const jsonPath = await writeFile({
123-
content: faker.string.sample(),
124-
path: faker.outputPath(`${fileName}_attribution.json`),
125-
});
126-
127-
setGlobalBackendState({
128-
resourceFilePath,
129-
attributionFilePath: jsonPath,
130-
});
131-
132-
await deleteAndCreateNewAttributionFileListener(mainWindow, () => {})();
133-
134-
expect(fs.existsSync(jsonPath)).toBeFalsy();
135-
expect(loadInputAndOutputFromFilePath).toHaveBeenCalledWith(
136-
expect.anything(),
137-
resourceFilePath,
138-
);
139-
});
140-
});
141-
142107
describe('getSelectBaseURLListener', () => {
143108
it('opens base url dialog and sends selected path to frontend', async () => {
144109
const mockCallback = jest.fn();

src/ElectronBackend/main/listeners.ts

+12-38
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,14 @@ export async function handleOpeningFile(
119119
filePath: string,
120120
onOpen: () => void,
121121
): Promise<void> {
122+
setLoadingState(mainWindow.webContents, true);
123+
122124
logger.info('Initializing global backend state');
123125
initializeGlobalBackendState(filePath, true);
124126

125127
await openFile(mainWindow, filePath, onOpen);
128+
129+
setLoadingState(mainWindow.webContents, false);
126130
}
127131

128132
export const importFileListener =
@@ -175,6 +179,8 @@ export const importFileConvertAndLoadListener =
175179
fileType: FileType,
176180
opossumFilePath: string,
177181
): Promise<boolean> => {
182+
setLoadingState(mainWindow.webContents, true);
183+
178184
try {
179185
if (!resourceFilePath.trim() || !fs.existsSync(resourceFilePath)) {
180186
throw new Error('Input file does not exist');
@@ -198,12 +204,14 @@ export const importFileConvertAndLoadListener =
198204
logger.info('Updating global backend state');
199205
initializeGlobalBackendState(opossumFilePath, true);
200206

201-
await openFile(mainWindow, opossumFilePath, onOpen, true);
207+
await openFile(mainWindow, opossumFilePath, onOpen);
202208

203209
return true;
204210
} catch (error) {
205211
sendListenerErrorToFrontend(mainWindow, error);
206212
return false;
213+
} finally {
214+
setLoadingState(mainWindow.webContents, false);
207215
}
208216
};
209217

@@ -234,29 +242,6 @@ function initializeGlobalBackendState(
234242
setGlobalBackendState(newGlobalBackendState);
235243
}
236244

237-
export const deleteAndCreateNewAttributionFileListener =
238-
(mainWindow: BrowserWindow, onOpen: () => void) =>
239-
async (): Promise<void> => {
240-
try {
241-
const globalBackendState = getGlobalBackendState();
242-
const resourceFilePath = globalBackendState.resourceFilePath as string;
243-
244-
logger.info(
245-
`Deleting attribution file and opening input file ${resourceFilePath}`,
246-
);
247-
if (globalBackendState.attributionFilePath) {
248-
fs.unlinkSync(globalBackendState.attributionFilePath);
249-
} else {
250-
throw new Error(
251-
`Failed to delete output file. Attribution file path is incorrect: ${globalBackendState.attributionFilePath}`,
252-
);
253-
}
254-
await openFile(mainWindow, resourceFilePath, onOpen);
255-
} catch (error) {
256-
await showListenerErrorInMessageBox(mainWindow, error);
257-
}
258-
};
259-
260245
export const selectBaseURLListener =
261246
(mainWindow: BrowserWindow) => async (): Promise<void> => {
262247
try {
@@ -283,21 +268,10 @@ export async function openFile(
283268
mainWindow: BrowserWindow,
284269
filePath: string,
285270
onOpen: () => void,
286-
isImport?: boolean,
287271
): Promise<void> {
288-
if (!isImport) {
289-
setLoadingState(mainWindow.webContents, true);
290-
}
291-
292-
try {
293-
await loadInputAndOutputFromFilePath(mainWindow, filePath);
294-
setTitle(mainWindow, filePath);
295-
onOpen();
296-
} finally {
297-
if (!isImport) {
298-
setLoadingState(mainWindow.webContents, false);
299-
}
300-
}
272+
await loadInputAndOutputFromFilePath(mainWindow, filePath);
273+
setTitle(mainWindow, filePath);
274+
onOpen();
301275
}
302276

303277
function setTitle(mainWindow: BrowserWindow, filePath: string): void {

src/ElectronBackend/main/main.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@
55
import { dialog, ipcMain, Menu, systemPreferences } from 'electron';
66
import os from 'os';
77

8-
import { IpcChannel } from '../../shared/ipc-channels';
8+
import { AllowedFrontendChannels, IpcChannel } from '../../shared/ipc-channels';
99
import { getMessageBoxContentForErrorsWrapper } from '../errorHandling/errorHandling';
1010
import { createWindow } from './createWindow';
1111
import {
12-
deleteAndCreateNewAttributionFileListener,
1312
exportFileListener,
1413
importFileConvertAndLoadListener,
1514
importFileSelectInputListener,
@@ -81,11 +80,12 @@ export async function main(): Promise<void> {
8180
importFileConvertAndLoadListener(mainWindow, activateMenuItems),
8281
);
8382
ipcMain.handle(IpcChannel.SaveFile, saveFileListener(mainWindow));
84-
ipcMain.handle(
85-
IpcChannel.DeleteFile,
86-
deleteAndCreateNewAttributionFileListener(mainWindow, activateMenuItems),
87-
);
8883
ipcMain.handle(IpcChannel.ExportFile, exportFileListener(mainWindow));
84+
ipcMain.handle(IpcChannel.StopLoading, () =>
85+
mainWindow.webContents.send(AllowedFrontendChannels.FileLoading, {
86+
isLoading: false,
87+
}),
88+
);
8989
ipcMain.handle(IpcChannel.OpenLink, openLinkListener);
9090
ipcMain.handle(IpcChannel.GetUserSettings, (_, key) =>
9191
UserSettings.get(key),

src/ElectronBackend/main/menu/fileMenu.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import {
1414
import { isFileLoaded } from '../../utils/getLoadedFile';
1515
import { getGlobalBackendState } from '../globalBackendState';
1616
import { getIconBasedOnTheme } from '../iconHelpers';
17-
import { importFileListener, selectBaseURLListener } from '../listeners';
17+
import {
18+
importFileListener,
19+
selectBaseURLListener,
20+
setLoadingState,
21+
} from '../listeners';
22+
import logger from '../logger';
1823
import { INITIALLY_DISABLED_ITEMS_INFO } from './initiallyDisabledMenuItems';
1924

2025
export const importFileFormats: Array<FileFormatInfo> = [
@@ -141,6 +146,8 @@ function getExportFollowUp(webContents: Electron.WebContents) {
141146
'icons/follow-up-black.png',
142147
),
143148
click: () => {
149+
setLoadingState(webContents, true);
150+
logger.info('Preparing data for follow-up export');
144151
webContents.send(
145152
AllowedFrontendChannels.ExportFileRequest,
146153
ExportType.FollowUp,
@@ -159,6 +166,8 @@ function getExportCompactBom(webContents: Electron.WebContents) {
159166
),
160167
label: INITIALLY_DISABLED_ITEMS_INFO.compactComponentList.label,
161168
click: () => {
169+
setLoadingState(webContents, true);
170+
logger.info('Preparing data for compact component list export');
162171
webContents.send(
163172
AllowedFrontendChannels.ExportFileRequest,
164173
ExportType.CompactBom,
@@ -177,6 +186,8 @@ function getExportDetailedBom(webContents: Electron.WebContents) {
177186
),
178187
label: INITIALLY_DISABLED_ITEMS_INFO.detailedComponentList.label,
179188
click: () => {
189+
setLoadingState(webContents, true);
190+
logger.info('Preparing data for detailed component list export');
180191
webContents.send(
181192
AllowedFrontendChannels.ExportFileRequest,
182193
ExportType.DetailedBom,
@@ -192,6 +203,8 @@ function getExportSpdxYaml(webContents: Electron.WebContents) {
192203
icon: getIconBasedOnTheme('icons/yaml-white.png', 'icons/yaml-black.png'),
193204
label: INITIALLY_DISABLED_ITEMS_INFO.spdxYAML.label,
194205
click: () => {
206+
setLoadingState(webContents, true);
207+
logger.info('Preparing data for SPDX (yaml) export');
195208
webContents.send(
196209
AllowedFrontendChannels.ExportFileRequest,
197210
ExportType.SpdxDocumentYaml,
@@ -202,11 +215,13 @@ function getExportSpdxYaml(webContents: Electron.WebContents) {
202215
};
203216
}
204217

205-
function getExportSpdsJson(webContents: Electron.WebContents) {
218+
function getExportSpdxJson(webContents: Electron.WebContents) {
206219
return {
207220
icon: getIconBasedOnTheme('icons/json-white.png', 'icons/json-black.png'),
208221
label: INITIALLY_DISABLED_ITEMS_INFO.spdxJSON.label,
209222
click: () => {
223+
setLoadingState(webContents, true);
224+
logger.info('Preparing data for SPDX (json) export');
210225
webContents.send(
211226
AllowedFrontendChannels.ExportFileRequest,
212227
ExportType.SpdxDocumentJson,
@@ -229,7 +244,7 @@ function getExportSubMenu(webContents: Electron.WebContents) {
229244
getExportCompactBom(webContents),
230245
getExportDetailedBom(webContents),
231246
getExportSpdxYaml(webContents),
232-
getExportSpdsJson(webContents),
247+
getExportSpdxJson(webContents),
233248
],
234249
};
235250
}

src/ElectronBackend/preload.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const electronAPI: ElectronAPI = {
2727
exportFile: (args) => ipcRenderer.invoke(IpcChannel.ExportFile, args),
2828
saveFile: (saveFileArgs) =>
2929
ipcRenderer.invoke(IpcChannel.SaveFile, saveFileArgs),
30+
stopLoading: () => ipcRenderer.invoke(IpcChannel.StopLoading),
3031
on: (channel, listener) => {
3132
ipcRenderer.on(channel, listener);
3233
return () => ipcRenderer.removeListener(channel, listener);

src/Frontend/Components/BackendCommunication/BackendCommunication.tsx

+1-13
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,11 @@ import {
2323
setBaseUrlsForSources,
2424
} from '../../state/actions/resource-actions/all-views-simple-actions';
2525
import { loadFromFile } from '../../state/actions/resource-actions/load-actions';
26-
import {
27-
openPopup,
28-
setLoading,
29-
} from '../../state/actions/view-actions/view-actions';
26+
import { openPopup } from '../../state/actions/view-actions/view-actions';
3027
import { useAppDispatch, useAppSelector } from '../../state/hooks';
3128
import { getBaseUrlsForSources } from '../../state/selectors/resource-selectors';
3229
import {
3330
ExportFileRequestListener,
34-
IsLoadingListener,
3531
LoggingListener,
3632
ShowImportDialogListener,
3733
useIpcRenderer,
@@ -99,14 +95,6 @@ export const BackendCommunication: React.FC = () => {
9995
);
10096
}
10197
}
102-
103-
useIpcRenderer<IsLoadingListener>(
104-
AllowedFrontendChannels.FileLoading,
105-
(_, { isLoading }) => {
106-
dispatch(setLoading(isLoading));
107-
},
108-
[dispatch],
109-
);
11098
useIpcRenderer(AllowedFrontendChannels.FileLoaded, fileLoadedListener, [
11199
dispatch,
112100
]);

src/Frontend/Components/ImportDialog/ImportDialog.tsx

+12-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import { text } from '../../../shared/text';
1212
import { getDotOpossumFilePath } from '../../../shared/write-file';
1313
import { closePopup } from '../../state/actions/view-actions/view-actions';
1414
import { useAppDispatch } from '../../state/hooks';
15-
import { LoggingListener, useIpcRenderer } from '../../util/use-ipc-renderer';
15+
import {
16+
IsLoadingListener,
17+
LoggingListener,
18+
useIpcRenderer,
19+
} from '../../util/use-ipc-renderer';
1620
import { FilePathInput } from '../FilePathInput/FilePathInput';
1721
import { LogDisplay } from '../LogDisplay/LogDisplay';
1822
import { NotificationPopup } from '../NotificationPopup/NotificationPopup';
@@ -27,7 +31,13 @@ export const ImportDialog: React.FC<ImportDialogProps> = ({ fileFormat }) => {
2731
const [inputFilePath, setInputFilePath] = useState<string>('');
2832
const [opossumFilePath, setOpossumFilePath] = useState<string>('');
2933

30-
const [isLoading, setIsLoading] = useState<boolean>(false);
34+
const [isLoading, setIsLoading] = useState(false);
35+
36+
useIpcRenderer<IsLoadingListener>(
37+
AllowedFrontendChannels.FileLoading,
38+
(_, { isLoading }) => setIsLoading(isLoading),
39+
[],
40+
);
3141

3242
const [logToDisplay, setLogToDisplay] = useState<Log | null>(null);
3343

@@ -82,8 +92,6 @@ export const ImportDialog: React.FC<ImportDialogProps> = ({ fileFormat }) => {
8292
}
8393

8494
async function onConfirm(): Promise<void> {
85-
setIsLoading(true);
86-
8795
const success = await window.electronAPI.importFileConvertAndLoad(
8896
inputFilePath,
8997
fileFormat.fileType,
@@ -93,8 +101,6 @@ export const ImportDialog: React.FC<ImportDialogProps> = ({ fileFormat }) => {
93101
if (success) {
94102
dispatch(closePopup());
95103
}
96-
97-
setIsLoading(false);
98104
}
99105

100106
return (

0 commit comments

Comments
 (0)