Globally inform about successful webUI updates

In case automatic webUI updates are disabled, the user gets informed about available updates
This commit is contained in:
schroda
2024-04-21 14:59:10 +02:00
parent 7725673dd7
commit c4d77d2325
4 changed files with 131 additions and 48 deletions

View File

@@ -302,6 +302,7 @@
"add": "Add",
"browse": "Browse",
"cancel": "Cancel",
"changelog": "Changelog",
"clear": "Clear",
"copy": "Copy",
"create": "Create",
@@ -317,6 +318,7 @@
"open_site": "Open Site",
"options": "Options",
"popular": "Popular",
"refresh": "Refresh",
"remove": "Remove",
"reset": "Reset",
"reset_to_default": "Reset to Default",
@@ -764,7 +766,8 @@
"channel": "$t(settings.webui.title.webui) channel",
"github": "$t(global.label.github) $t(settings.webui.title.webui)",
"update_failure": "Could not update $t(settings.webui.title.webui)",
"update_success": "Updated $t(settings.webui.title.webui) to version {{version}}. Refresh required",
"update_success": "Updated $t(settings.webui.title.webui) to version {{version}}.",
"updated": "Updated version",
"version": "$t(settings.webui.title.webui) version"
}
}

View File

@@ -39,6 +39,7 @@ import { Migrate } from '@/screens/Migrate.tsx';
import { DeviceSetting } from '@/components/settings/DeviceSetting.tsx';
import { TrackingSettings } from '@/screens/settings/TrackingSettings.tsx';
import { TrackerOAuthLogin } from '@/screens/TrackerOAuthLogin.tsx';
import { WebUIUpdateChecker } from '@/components/util/WebUIUpdateChecker.tsx';
if (process.env.NODE_ENV !== 'production') {
// Adds messages only in a dev environment
@@ -74,6 +75,7 @@ export const App: React.FC = () => (
<AppContext>
<ScrollToTop />
<ServerUpdateChecker />
<WebUIUpdateChecker />
<BackgroundSubscriptions />
<CssBaseline />
<DefaultNavBar />

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useTranslation } from 'react-i18next';
import { useEffect, useState } from 'react';
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogActions from '@mui/material/DialogActions';
import Button from '@mui/material/Button';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
import { UpdateState, WebUiChannel, WebUiUpdateStatus } from '@/lib/graphql/generated/graphql.ts';
import { useLocalStorage } from '@/util/useStorage.tsx';
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { makeToast } from '@/components/util/Toast.tsx';
import { ABOUT_WEBUI, WEBUI_UPDATE_CHECK } from '@/lib/graphql/Fragments.ts';
export const WebUIUpdateChecker = () => {
const { t } = useTranslation();
const [webUIVersion, setWebUIVersion] = useLocalStorage<string>('webUIVersion');
const [open, setOpen] = useState(false);
const { data: webUIUpdateStatusData } = requestManager.useGetWebUIUpdateStatus();
const { state: webUIUpdateState, ...updateStatus } = (webUIUpdateStatusData?.getWebUIUpdateStatus ?? {
state: UpdateState.Idle,
progress: 0,
info: undefined,
}) satisfies OptionalProperty<WebUiUpdateStatus, 'info'>;
const changelogUrl =
updateStatus.info?.channel === WebUiChannel.Stable
? `https://github.com/Suwayomi/Suwayomi-WebUI/releases/tag/${updateStatus.info?.tag}`
: `https://github.com/Suwayomi/Suwayomi-WebUI/issues/749`;
useEffect(() => {
const isError = webUIUpdateState === UpdateState.Error;
if (isError) {
makeToast(t('settings.about.webui.label.update_failure'), 'error');
}
const updateFinished = webUIUpdateState === UpdateState.Finished;
const resetUpdateStatus = isError || updateFinished;
if (resetUpdateStatus) {
requestManager
.resetWebUIUpdateStatus()
.response.catch(defaultPromiseErrorHandler('WebUIUpdateChecker::resetWebUIUpdateStatus'));
}
if (!updateFinished) {
return;
}
if (!updateStatus.info) {
return;
}
requestManager.graphQLClient.client.cache.writeFragment({
fragment: ABOUT_WEBUI,
data: {
__typename: 'AboutWebUI',
channel: webUIUpdateStatusData!.getWebUIUpdateStatus.info.channel,
tag: webUIUpdateStatusData!.getWebUIUpdateStatus.info.tag,
},
});
requestManager.graphQLClient.client.cache.writeFragment({
fragment: WEBUI_UPDATE_CHECK,
data: {
__typename: 'WebUIUpdateCheck',
channel: webUIUpdateStatusData!.getWebUIUpdateStatus.info.channel,
tag: webUIUpdateStatusData!.getWebUIUpdateStatus.info.tag,
updateAvailable: false,
},
});
const newVersion = updateStatus.info.tag;
const isSameAsCurrent = webUIVersion === newVersion;
setWebUIVersion(newVersion);
if (isSameAsCurrent) {
return;
}
setOpen(true);
}, [webUIUpdateState]);
const handleUpdate = open && webUIUpdateState === UpdateState.Idle;
if (!handleUpdate) {
return null;
}
return (
<Dialog open={open}>
<DialogTitle>{t('settings.about.webui.label.updated')}</DialogTitle>
<DialogContent>
<DialogContentText>
{t('settings.about.webui.label.update_success', {
version: webUIVersion,
})}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button href={changelogUrl} target="_blank">
{t('global.button.changelog')}
</Button>
<Button
onClick={() => {
setOpen(false);
window.location.reload();
}}
variant="contained"
>
{t('global.button.refresh')}
</Button>
</DialogActions>
</Dialog>
);
};

View File

@@ -27,8 +27,6 @@ import { ListItemLink } from '@/components/util/ListItemLink';
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder';
import { GetAboutQuery, UpdateState } from '@/lib/graphql/generated/graphql.ts';
import { ABOUT_WEBUI, WEBUI_UPDATE_CHECK } from '@/lib/graphql/Fragments.ts';
import { makeToast } from '@/components/util/Toast.tsx';
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
type AboutServer = GetAboutQuery['aboutServer'];
@@ -226,51 +224,6 @@ export function About() {
progress: 0,
};
useEffect(() => {
const isError = webUIUpdateState === UpdateState.Error;
if (isError) {
makeToast(t('settings.about.webui.label.update_failure'), 'error');
}
const updateFinished = webUIUpdateState === UpdateState.Finished;
const resetUpdateStatus = isError || updateFinished;
if (resetUpdateStatus) {
requestManager
.resetWebUIUpdateStatus()
.response.catch(defaultPromiseErrorHandler('About::resetWebUIUpdateStatus'));
}
if (!updateFinished) {
return;
}
makeToast(
t('settings.about.webui.label.update_success', {
version: webUIUpdateStatusData!.getWebUIUpdateStatus.info.tag,
}),
'success',
);
requestManager.graphQLClient.client.cache.writeFragment({
fragment: ABOUT_WEBUI,
data: {
__typename: 'AboutWebUI',
channel: webUIUpdateStatusData!.getWebUIUpdateStatus.info.channel,
tag: webUIUpdateStatusData!.getWebUIUpdateStatus.info.tag,
},
});
requestManager.graphQLClient.client.cache.writeFragment({
fragment: WEBUI_UPDATE_CHECK,
data: {
__typename: 'WebUIUpdateCheck',
channel: webUIUpdateStatusData!.getWebUIUpdateStatus.info.channel,
tag: webUIUpdateStatusData!.getWebUIUpdateStatus.info.tag,
updateAvailable: false,
},
});
}, [webUIUpdateState]);
if (!aboutServer || !aboutWebUI) {
return <LoadingPlaceholder />;
}