Fix/install external extension does not update extension list (#580)
* Update extension list after installing external extension file The cache was never updated after the installation * Make it possible to install external extension while having an empty list * Show toasts while having an empty extension list * Use correct extension id * Update extension action after manual file installation When installing an external extension the action button did not get updated due to this being an internal state of the ExtensionCard. By including this in the key, it gets ensured that the component will get correctly updated
This commit is contained in:
@@ -1005,12 +1005,68 @@ export class RequestManager {
|
||||
extensionFile: File,
|
||||
options?: MutationOptions<InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables>,
|
||||
): AbortableApolloMutationResponse<InstallExternalExtensionMutation> {
|
||||
return this.doRequest<InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables>(
|
||||
const result = this.doRequest<InstallExternalExtensionMutation, InstallExternalExtensionMutationVariables>(
|
||||
GQLMethod.MUTATION,
|
||||
INSTALL_EXTERNAL_EXTENSION,
|
||||
{ file: extensionFile },
|
||||
{ refetchQueries: [GET_EXTENSIONS], ...options },
|
||||
);
|
||||
|
||||
result.response.then((response) => {
|
||||
this.graphQLClient.client.cache.evict({ fieldName: 'sources' });
|
||||
const cachedExtensions = this.cache.getResponseFor<MutationResult<GetExtensionsFetchMutation>>(
|
||||
EXTENSION_LIST_CACHE_KEY,
|
||||
undefined,
|
||||
);
|
||||
|
||||
const installedExtension = response.data?.installExternalExtension.extension;
|
||||
|
||||
if (!cachedExtensions || !cachedExtensions.data) {
|
||||
this.cache.cacheResponse(EXTENSION_LIST_CACHE_KEY, undefined, {
|
||||
data: {
|
||||
fetchExtensions: {
|
||||
extensions: [installedExtension],
|
||||
},
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const isExtensionCached = !!cachedExtensions.data.fetchExtensions.extensions.find(
|
||||
(extension) => installedExtension?.pkgName === extension.pkgName,
|
||||
);
|
||||
|
||||
const updatedCachedExtensions: MutationResult<GetExtensionsFetchMutation> = {
|
||||
...cachedExtensions,
|
||||
data: {
|
||||
...cachedExtensions.data,
|
||||
fetchExtensions: {
|
||||
...cachedExtensions.data.fetchExtensions,
|
||||
extensions: isExtensionCached
|
||||
? cachedExtensions.data.fetchExtensions.extensions.map((extension) => {
|
||||
const isUpdatedExtension = installedExtension?.pkgName === extension.pkgName;
|
||||
if (!isUpdatedExtension) {
|
||||
return extension;
|
||||
}
|
||||
|
||||
return {
|
||||
...extension,
|
||||
...installedExtension,
|
||||
hasUpdate: installedExtension?.versionCode < extension.versionCode,
|
||||
};
|
||||
})
|
||||
: [
|
||||
...cachedExtensions.data.fetchExtensions.extensions,
|
||||
installedExtension as (typeof cachedExtensions.data.fetchExtensions.extensions)[number],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
this.cache.cacheResponse(EXTENSION_LIST_CACHE_KEY, undefined, updatedCachedExtensions);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public updateExtension(
|
||||
|
||||
@@ -160,6 +160,7 @@ export function Extensions() {
|
||||
requestManager
|
||||
.installExternalExtension(file)
|
||||
.response.then(() => {
|
||||
handleExtensionUpdate();
|
||||
makeToast(t('extension.label.installed_successfully'), 'success');
|
||||
})
|
||||
.catch(() => makeToast(t('extension.label.installation_failed'), 'error'));
|
||||
@@ -207,25 +208,8 @@ export function Extensions() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!allExtensions && (isLoading || !called)) {
|
||||
return <LoadingPlaceholder />;
|
||||
}
|
||||
|
||||
const showAddRepoInfo = !allExtensions?.length && !areReposDefined;
|
||||
if (showAddRepoInfo) {
|
||||
return (
|
||||
<Stack sx={{ paddingTop: '20px' }} alignItems="center" justifyContent="center" rowGap="10px">
|
||||
<Typography>{t('extension.label.add_repository_info')}</Typography>
|
||||
<Button component={Link} variant="contained" to="/settings/extensionSettings">
|
||||
{t('settings.title')}
|
||||
</Button>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{toasts}
|
||||
const FileInputComponent = useMemo(
|
||||
() => (
|
||||
<input
|
||||
type="file"
|
||||
style={{ display: 'none' }}
|
||||
@@ -237,6 +221,34 @@ export function Extensions() {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
if (!allExtensions && (isLoading || !called)) {
|
||||
return <LoadingPlaceholder />;
|
||||
}
|
||||
|
||||
const showAddRepoInfo = !allExtensions?.length && !areReposDefined;
|
||||
if (showAddRepoInfo) {
|
||||
return (
|
||||
<>
|
||||
{toasts}
|
||||
{FileInputComponent}
|
||||
<Stack sx={{ paddingTop: '20px' }} alignItems="center" justifyContent="center" rowGap="10px">
|
||||
<Typography>{t('extension.label.add_repository_info')}</Typography>
|
||||
<Button component={Link} variant="contained" to="/settings/extensionSettings">
|
||||
{t('settings.title')}
|
||||
</Button>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{toasts}
|
||||
{FileInputComponent}
|
||||
<StyledGroupedVirtuoso
|
||||
style={{
|
||||
// override Virtuoso default values and set them with class
|
||||
@@ -274,7 +286,10 @@ export function Extensions() {
|
||||
const item = visibleExtensions[index];
|
||||
|
||||
return (
|
||||
<StyledGroupItemWrapper key={item.apkName} isLastItem={index === visibleExtensions.length - 1}>
|
||||
<StyledGroupItemWrapper
|
||||
key={`${item.pkgName}_${item.isInstalled}_${item.isObsolete}_${item.hasUpdate}`}
|
||||
isLastItem={index === visibleExtensions.length - 1}
|
||||
>
|
||||
<ExtensionCard
|
||||
extension={item}
|
||||
handleUpdate={handleExtensionUpdate}
|
||||
|
||||
Reference in New Issue
Block a user