Skip to content

Commit

Permalink
Merge pull request #1524 from vasily-pozdnyakov/check_for_new_release
Browse files Browse the repository at this point in the history
Added functionality to check for newer release
  • Loading branch information
benedikt-richter authored Mar 31, 2023
2 parents 330d122 + 2d50c3c commit 6f2a682
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 2 deletions.
8 changes: 8 additions & 0 deletions src/ElectronBackend/main/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ export function createMenu(mainWindow: BrowserWindow): Menu {
await shell.openPath(app.getPath('logs'));
},
},
{
label: 'Check for updates',
click(): void {
webContents.send(AllowedFrontendChannels.ShowUpdateAppPopup, {
showUpdateAppPopup: true,
});
},
},
],
},
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,15 @@ export function BackendCommunication(): ReactElement | null {
}
}

function showUpdateAppPopupListener(
event: IpcRendererEvent,
showUpdateAppPopup: boolean
): void {
if (showUpdateAppPopup) {
dispatch(openPopup(PopupType.UpdateAppPopup));
}
}

function setBaseURLForRootListener(
event: IpcRendererEvent,
baseURLForRootArgs: BaseURLForRootArgs
Expand Down Expand Up @@ -313,6 +322,11 @@ export function BackendCommunication(): ReactElement | null {
showFileSupportPopupListener,
[dispatch]
);
useIpcRenderer(
AllowedFrontendChannels.ShowUpdateAppPopup,
showUpdateAppPopupListener,
[dispatch]
);

return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Attributions, ExportType } from '../../../../shared/shared-types';
describe('BackendCommunication', () => {
it('renders an Open file icon', () => {
renderComponentWithStore(<BackendCommunication />);
const expectedNumberOfCalls = 11;
const expectedNumberOfCalls = 12;
expect(window.electronAPI.on).toHaveBeenCalledTimes(expectedNumberOfCalls);
expect(window.electronAPI.on).toHaveBeenCalledWith(
AllowedFrontendChannels.FileLoaded,
Expand Down
3 changes: 3 additions & 0 deletions src/Frontend/Components/GlobalPopup/GlobalPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { ChangedInputFilePopup } from '../ChangedInputFilePopup/ChangedInputFile
import { AttributionWizardPopup } from '../AttributionWizardPopup/AttributionWizardPopup';
import { FileSupportPopup } from '../FileSupportPopup/FileSupportPopup';
import { FileSupportDotOpossumAlreadyExistsPopup } from '../FileSupportDotOpossumAlreadyExistsPopup/FileSupportDotOpossumAlreadyExistsPopup';
import { UpdateAppPopup } from '../UpdateAppPopup/UpdateAppPopup';

function getPopupComponent(popupType: PopupType | null): ReactElement | null {
switch (popupType) {
Expand Down Expand Up @@ -58,6 +59,8 @@ function getPopupComponent(popupType: PopupType | null): ReactElement | null {
return <FileSupportPopup />;
case PopupType.FileSupportDotOpossumAlreadyExistsPopup:
return <FileSupportDotOpossumAlreadyExistsPopup />;
case PopupType.UpdateAppPopup:
return <UpdateAppPopup />;
default:
return null;
}
Expand Down
22 changes: 22 additions & 0 deletions src/Frontend/Components/GlobalPopup/__tests__/GlobalPopup.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from '../../../state/actions/resource-actions/all-views-simple-actions';
import { setSelectedResourceId } from '../../../state/actions/resource-actions/audit-view-simple-actions';
import { openAttributionWizardPopup } from '../../../state/actions/popup-actions/popup-actions';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

describe('The GlobalPopUp', () => {
it('does not open by default', () => {
Expand Down Expand Up @@ -210,4 +211,25 @@ describe('The GlobalPopUp', () => {
const header = 'Warning: Outdated input file format';
expect(screen.getByText(header)).toBeInTheDocument();
});

it('opens the UpdateAppPopup', () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const { store } = renderComponentWithStore(
<QueryClientProvider client={queryClient}>
<GlobalPopup />
</QueryClientProvider>
);
act(() => {
store.dispatch(openPopup(PopupType.UpdateAppPopup));
});

const header = 'Check for updates';
expect(screen.getByText(header)).toBeInTheDocument();
});
});
2 changes: 1 addition & 1 deletion src/Frontend/Components/TopBar/__tests__/TopBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { setResources } from '../../../state/actions/resource-actions/all-views-
describe('TopBar', () => {
it('renders an Open file icon', () => {
const { store } = renderComponentWithStore(<TopBar />);
const totalNumberOfCalls = 11;
const totalNumberOfCalls = 12;
expect(window.electronAPI.on).toHaveBeenCalledTimes(totalNumberOfCalls);
expect(window.electronAPI.on).toHaveBeenCalledWith(
AllowedFrontendChannels.FileLoaded,
Expand Down
78 changes: 78 additions & 0 deletions src/Frontend/Components/UpdateAppPopup/UpdateAppPopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
//
// SPDX-License-Identifier: Apache-2.0

import React, { ReactElement } from 'react';
import { NotificationPopup } from '../NotificationPopup/NotificationPopup';
import { useAppDispatch } from '../../state/hooks';
import { closePopup } from '../../state/actions/view-actions/view-actions';
import { ButtonText } from '../../enums/enums';
import commitInfo from '../../../commitInfo.json';
import MuiLink from '@mui/material/Link';
import { openUrl } from '../../util/open-url';
import MuiTypography from '@mui/material/Typography';
import { searchLatestReleaseNameAndUrl } from './update-app-popup-helpers';
import { useQuery } from '@tanstack/react-query';
import { Alert } from '../Alert/Alert';
import { Spinner } from '../Spinner/Spinner';

export function UpdateAppPopup(): ReactElement {
const dispatch = useAppDispatch();

function close(): void {
dispatch(closePopup());
}

const { isLoading, data, isError, error } = useQuery(
['latestReleaseNameSearch'],
() => searchLatestReleaseNameAndUrl(),
{
refetchOnWindowFocus: false,
}
);

const content = !isError ? (
isLoading ? (
<Spinner />
) : data ? (
data.name === commitInfo.commitInfo ? (
'You have the latest version of the app.'
) : (
<>
<MuiTypography>
There is a new release! You can download it using the following
link:
<br />
<MuiLink component="button" onClick={(): void => openUrl(data.url)}>
{data.name}
</MuiLink>
</MuiTypography>
</>
)
) : (
'No information found.'
)
) : (
<Alert
errorMessage={`Failed while fetching release data${
error instanceof Error ? `: ${error.message}` : ''
}`}
/>
);

return (
<NotificationPopup
content={content}
header={'Check for updates'}
isOpen={true}
fullWidth={false}
rightButtonConfig={{
onClick: close,
buttonText: ButtonText.Close,
}}
onBackdropClick={close}
onEscapeKeyDown={close}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
//
// SPDX-License-Identifier: Apache-2.0

import React from 'react';
import { renderComponentWithStore } from '../../../test-helpers/render-component-with-store';
import { UpdateAppPopup } from '../UpdateAppPopup';
import { screen } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios';
import commitInfo from '../../../../commitInfo.json';

describe('UpdateAppPopup', () => {
const okStatus = 200;
const notFoundStatus = 404;
const axiosMock = new MockAdapter(axios);
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});

it('shows the popup with a link to a new release', async () => {
axiosMock
.onGet(
'https://api.github.com/repos/opossum-tool/OpossumUI/releases/latest'
)
.replyOnce(okStatus, {
name: 'Latest release',
html_url: 'some url',
});
renderComponentWithStore(
<QueryClientProvider client={queryClient}>
<UpdateAppPopup />
</QueryClientProvider>
);
expect(screen.getByText('Check for updates'));
expect(
await screen.findByText(
'There is a new release! You can download it using the following link:'
)
);
expect(await screen.findByText('Latest release'));
});

it('shows the popup with no newer release', async () => {
axiosMock
.onGet(
'https://api.github.com/repos/opossum-tool/OpossumUI/releases/latest'
)
.replyOnce(okStatus, {
name: commitInfo.commitInfo,
html_url: 'some url',
});
renderComponentWithStore(
<QueryClientProvider client={queryClient}>
<UpdateAppPopup />
</QueryClientProvider>
);
expect(screen.getByText('Check for updates'));
expect(await screen.findByText('You have the latest version of the app.'));
});

it('shows the popup with no info found', async () => {
axiosMock
.onGet(
'https://api.github.com/repos/opossum-tool/OpossumUI/releases/latest'
)
.replyOnce(okStatus, null);
renderComponentWithStore(
<QueryClientProvider client={queryClient}>
<UpdateAppPopup />
</QueryClientProvider>
);
expect(screen.getByText('Check for updates'));
expect(await screen.findByText('No information found.'));
});

it('shows the popup with error', async () => {
axiosMock
.onGet(
'https://api.github.com/repos/opossum-tool/OpossumUI/releases/latest'
)
.replyOnce(notFoundStatus);
renderComponentWithStore(
<QueryClientProvider client={queryClient}>
<UpdateAppPopup />
</QueryClientProvider>
);
expect(screen.getByText('Check for updates'));
expect(
await screen.findByText(
'Failed while fetching release data: Request failed with status code 404'
)
);
});
});
21 changes: 21 additions & 0 deletions src/Frontend/Components/UpdateAppPopup/update-app-popup-helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
//
// SPDX-License-Identifier: Apache-2.0

import axios from 'axios';

export async function searchLatestReleaseNameAndUrl(): Promise<{
name: string;
url: string;
} | null> {
const response = await axios.get(
'https://api.github.com/repos/opossum-tool/OpossumUI/releases/latest'
);
if (!response.data) {
return null;
}
const name = response.data.name as string;
const url = response.data.html_url as string;
return { name, url };
}
1 change: 1 addition & 0 deletions src/Frontend/enums/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum PopupType {
AttributionWizardPopup = 'AttributionWizardPopup',
FileSupportPopup = 'FileSupportPopup',
FileSupportDotOpossumAlreadyExistsPopup = 'FileSupportDotOpossumAlreadyExistsPopup',
UpdateAppPopup = 'UpdateAppPopup',
}

export enum SavePackageInfoOperation {
Expand Down
1 change: 1 addition & 0 deletions src/shared/ipc-channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ export enum AllowedFrontendChannels {
ShowSearchPopup = 'show-search-pop-up',
ShowProjectMetadataPopup = 'show-project-metadata-pop-up',
ShowProjectStatisticsPopup = 'show-project-statistics-pop-up',
ShowUpdateAppPopup = 'show-update-app-pop-up',
}

0 comments on commit 6f2a682

Please sign in to comment.