Handle extension update failure (#530)
The failure was never handled and instead, the update was infinitely stuck in progress.
This commit is contained in:
@@ -17,6 +17,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { PartialExtension, TranslationKey } from '@/typings';
|
import { PartialExtension, TranslationKey } from '@/typings';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/util/defaultPromiseErrorHandler.ts';
|
||||||
|
import { makeToast } from '@/components/util/Toast.tsx';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
extension: PartialExtension;
|
extension: PartialExtension;
|
||||||
@@ -62,6 +63,30 @@ const INSTALLED_STATE_TO_TRANSLATION_KEY_MAP: { [installedState in InstalledStat
|
|||||||
[InstalledState.INSTALLING]: 'extension.state.label.installing',
|
[InstalledState.INSTALLING]: 'extension.state.label.installing',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
const EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP: {
|
||||||
|
[action in ExtensionAction]: TranslationKey;
|
||||||
|
} = {
|
||||||
|
[ExtensionAction.UPDATE]: 'extension.label.update_failed',
|
||||||
|
[ExtensionAction.INSTALL]: 'extension.label.installation_failed',
|
||||||
|
[ExtensionAction.UNINSTALL]: 'extension.label.uninstallation_failed',
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInstalledState = (
|
||||||
|
isInstalled: boolean,
|
||||||
|
isObsolete: boolean,
|
||||||
|
hasUpdate: boolean,
|
||||||
|
): ExtensionAction | ExtensionState.OBSOLETE => {
|
||||||
|
if (isObsolete) {
|
||||||
|
return InstalledState.OBSOLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasUpdate) {
|
||||||
|
return InstalledState.UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isInstalled ? InstalledState.UNINSTALL : InstalledState.INSTALL;
|
||||||
|
};
|
||||||
|
|
||||||
export function ExtensionCard(props: IProps) {
|
export function ExtensionCard(props: IProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -69,15 +94,9 @@ export function ExtensionCard(props: IProps) {
|
|||||||
extension: { name, lang, versionName, isInstalled, hasUpdate, isObsolete, pkgName, iconUrl, isNsfw },
|
extension: { name, lang, versionName, isInstalled, hasUpdate, isObsolete, pkgName, iconUrl, isNsfw },
|
||||||
handleUpdate,
|
handleUpdate,
|
||||||
} = props;
|
} = props;
|
||||||
const [installedState, setInstalledState] = useState<InstalledStates>(() => {
|
const [installedState, setInstalledState] = useState<InstalledStates>(
|
||||||
if (isObsolete) {
|
getInstalledState(isInstalled, isObsolete, hasUpdate),
|
||||||
return InstalledState.OBSOLETE;
|
);
|
||||||
}
|
|
||||||
if (hasUpdate) {
|
|
||||||
return InstalledState.UPDATE;
|
|
||||||
}
|
|
||||||
return isInstalled ? InstalledState.UNINSTALL : InstalledState.INSTALL;
|
|
||||||
});
|
|
||||||
|
|
||||||
const langPress = lang === 'all' ? t('extension.language.all') : lang.toUpperCase();
|
const langPress = lang === 'all' ? t('extension.language.all') : lang.toUpperCase();
|
||||||
|
|
||||||
@@ -85,23 +104,28 @@ export function ExtensionCard(props: IProps) {
|
|||||||
const nextAction = EXTENSION_ACTION_TO_NEXT_ACTION_MAP[action];
|
const nextAction = EXTENSION_ACTION_TO_NEXT_ACTION_MAP[action];
|
||||||
const state = EXTENSION_ACTION_TO_STATE_MAP[action];
|
const state = EXTENSION_ACTION_TO_STATE_MAP[action];
|
||||||
|
|
||||||
setInstalledState(state);
|
try {
|
||||||
switch (action) {
|
setInstalledState(state);
|
||||||
case ExtensionAction.INSTALL:
|
switch (action) {
|
||||||
await requestManager.updateExtension(pkgName, { install: true }).response;
|
case ExtensionAction.INSTALL:
|
||||||
break;
|
await requestManager.updateExtension(pkgName, { install: true }).response;
|
||||||
case ExtensionAction.UNINSTALL:
|
break;
|
||||||
await requestManager.updateExtension(pkgName, { uninstall: true }).response;
|
case ExtensionAction.UNINSTALL:
|
||||||
break;
|
await requestManager.updateExtension(pkgName, { uninstall: true }).response;
|
||||||
case ExtensionAction.UPDATE:
|
break;
|
||||||
await requestManager.updateExtension(pkgName, { update: true }).response;
|
case ExtensionAction.UPDATE:
|
||||||
break;
|
await requestManager.updateExtension(pkgName, { update: true }).response;
|
||||||
default:
|
break;
|
||||||
throw new Error(`Unexpected ExtensionAction "${action}"`);
|
default:
|
||||||
}
|
throw new Error(`Unexpected ExtensionAction "${action}"`);
|
||||||
setInstalledState(nextAction);
|
}
|
||||||
|
setInstalledState(nextAction);
|
||||||
|
|
||||||
handleUpdate();
|
handleUpdate();
|
||||||
|
} catch (e) {
|
||||||
|
setInstalledState(getInstalledState(isInstalled, isObsolete, hasUpdate));
|
||||||
|
makeToast(t(EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP[action]), 'error');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleButtonClick() {
|
function handleButtonClick() {
|
||||||
|
|||||||
@@ -225,7 +225,9 @@
|
|||||||
"label": {
|
"label": {
|
||||||
"installation_failed": "Could not install the extension",
|
"installation_failed": "Could not install the extension",
|
||||||
"installed_successfully": "Extension installed",
|
"installed_successfully": "Extension installed",
|
||||||
"installing_file": "Installing extension file…"
|
"installing_file": "Installing extension file…",
|
||||||
|
"uninstallation_failed": "Could not uninstall the extension",
|
||||||
|
"update_failed": "Could not update the extension"
|
||||||
},
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"all": "All",
|
"all": "All",
|
||||||
|
|||||||
Reference in New Issue
Block a user