Cleanup "Extensions"
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { fromEvent } from 'file-selector';
|
import { fromEvent } from 'file-selector';
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
@@ -116,51 +116,36 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
|||||||
const { pathname, search, state } = useLocation<{ selectedExtensionPkg?: TExtension['pkgName'] }>();
|
const { pathname, search, state } = useLocation<{ selectedExtensionPkg?: TExtension['pkgName'] }>();
|
||||||
const selectedExtensionPkg = state?.selectedExtensionPkg;
|
const selectedExtensionPkg = state?.selectedExtensionPkg;
|
||||||
|
|
||||||
const setSelectedExtensionPkg = (newPkg: TExtension['pkgName'] | undefined) => {
|
|
||||||
navigate(pathname + search, {
|
|
||||||
replace: true,
|
|
||||||
state: {
|
|
||||||
selectedExtensionPkg: newPkg,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: serverSettingsData,
|
data: serverSettingsData,
|
||||||
loading: areServerSettingsLoading,
|
loading: areServerSettingsLoading,
|
||||||
error: serverSettingsError,
|
error: serverSettingsError,
|
||||||
refetch: refetchServerSettings,
|
refetch: refetchServerSettings,
|
||||||
} = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true });
|
} = requestManager.useGetServerSettings({ notifyOnNetworkStatusChange: true });
|
||||||
const areReposDefined = !!serverSettingsData?.settings.extensionRepos.length;
|
const [fetchExtensions, { data, loading: areExtensionsLoading, error: extensionsError }] =
|
||||||
const areMultipleReposInUse = (serverSettingsData?.settings.extensionRepos.length ?? 0) > 1;
|
requestManager.useExtensionListFetch();
|
||||||
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
const [shownLangs, setShownLangs] = useLocalStorage<string[]>('shownExtensionLangs', extensionDefaultLangs());
|
const [shownLangs, setShownLangs] = useLocalStorage<string[]>('shownExtensionLangs', extensionDefaultLangs());
|
||||||
const [showNsfw] = useLocalStorage<boolean>('showNsfw', true);
|
const [showNsfw] = useLocalStorage<boolean>('showNsfw', true);
|
||||||
const [query] = useQueryParam('query', StringParam);
|
const [query] = useQueryParam('query', StringParam);
|
||||||
|
|
||||||
const [refetchExtensions, setRefetchExtensions] = useState({});
|
|
||||||
const [fetchExtensions, { data, loading: areExtensionsLoading, error: extensionsError }] =
|
|
||||||
requestManager.useExtensionListFetch();
|
|
||||||
const allExtensions = data?.fetchExtensions?.extensions;
|
|
||||||
|
|
||||||
const [updatingExtensionIds, setUpdatingExtensionIds] = useState<string[]>([]);
|
const [updatingExtensionIds, setUpdatingExtensionIds] = useState<string[]>([]);
|
||||||
|
const [refetchExtensions, setRefetchExtensions] = useState({});
|
||||||
|
|
||||||
const handleExtensionUpdate = useCallback(() => setRefetchExtensions({}), []);
|
const isLoading = areServerSettingsLoading || areExtensionsLoading;
|
||||||
|
const error = serverSettingsError ?? extensionsError;
|
||||||
|
|
||||||
useEffect(() => {
|
const areReposDefined = !!serverSettingsData?.settings.extensionRepos.length;
|
||||||
fetchExtensions();
|
const areMultipleReposInUse = (serverSettingsData?.settings.extensionRepos.length ?? 0) > 1;
|
||||||
}, [refetchExtensions]);
|
|
||||||
|
|
||||||
|
const allExtensions = data?.fetchExtensions?.extensions;
|
||||||
const allLangs = useMemo(() => getLanguagesFromExtensions(allExtensions ?? []), [allExtensions]);
|
const allLangs = useMemo(() => getLanguagesFromExtensions(allExtensions ?? []), [allExtensions]);
|
||||||
|
|
||||||
const filteredExtensions = useMemo(
|
const filteredExtensions = useMemo(
|
||||||
() => filterExtensions(allExtensions ?? [], shownLangs, showNsfw, query),
|
() => filterExtensions(allExtensions ?? [], shownLangs, showNsfw, query),
|
||||||
[allExtensions, shownLangs, shownLangs, query],
|
[allExtensions, shownLangs, shownLangs, query],
|
||||||
);
|
);
|
||||||
|
|
||||||
const groupedExtensions = useMemo(() => groupExtensionsByLanguage(filteredExtensions), [filteredExtensions]);
|
const groupedExtensions = useMemo(() => groupExtensionsByLanguage(filteredExtensions), [filteredExtensions]);
|
||||||
|
|
||||||
const groupCounts = useMemo(
|
const groupCounts = useMemo(
|
||||||
() => groupedExtensions.map((extensionGroup) => extensionGroup[EXTENSIONS].length),
|
() => groupedExtensions.map((extensionGroup) => extensionGroup[EXTENSIONS].length),
|
||||||
[groupedExtensions],
|
[groupedExtensions],
|
||||||
@@ -176,10 +161,21 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
|||||||
useCallback((index) => visibleExtensions[index].pkgName, [visibleExtensions]),
|
useCallback((index) => visibleExtensions[index].pkgName, [visibleExtensions]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleExtensionUpdate = useCallback(() => setRefetchExtensions({}), []);
|
||||||
|
|
||||||
|
const setSelectedExtensionPkg = (newPkg: TExtension['pkgName'] | undefined) => {
|
||||||
|
navigate(pathname + search, {
|
||||||
|
replace: true,
|
||||||
|
state: {
|
||||||
|
selectedExtensionPkg: newPkg,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const submitExternalExtension = (file: File) => {
|
const submitExternalExtension = (file: File) => {
|
||||||
if (file.name.toLowerCase().endsWith('apk')) {
|
if (!file.name.toLowerCase().endsWith('apk')) {
|
||||||
if (inputRef.current) {
|
makeToast(t('global.error.label.invalid_file_type'), 'error');
|
||||||
inputRef.current.value = '';
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeToast(t('extension.label.installing_file'), 'info');
|
makeToast(t('extension.label.installing_file'), 'info');
|
||||||
@@ -190,17 +186,35 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
|||||||
makeToast(t('extension.label.installed_successfully'), 'success');
|
makeToast(t('extension.label.installed_successfully'), 'success');
|
||||||
})
|
})
|
||||||
.catch((e) => makeToast(t('extension.label.installation_failed'), 'error', getErrorMessage(e)));
|
.catch((e) => makeToast(t('extension.label.installation_failed'), 'error', getErrorMessage(e)));
|
||||||
} else {
|
|
||||||
makeToast(t('global.error.label.invalid_file_type'), 'error');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchExtensions();
|
||||||
|
}, [refetchExtensions]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setAction(
|
setAction(
|
||||||
<>
|
<>
|
||||||
<AppbarSearch />
|
<AppbarSearch />
|
||||||
<CustomTooltip title={t('extension.action.label.install_external')}>
|
<CustomTooltip title={t('extension.action.label.install_external')}>
|
||||||
<IconButton onClick={() => inputRef.current?.click()} color="inherit">
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.style.display = 'none';
|
||||||
|
input.type = 'file';
|
||||||
|
input.onchange = () => {
|
||||||
|
const file = input.files?.[0];
|
||||||
|
if (file) {
|
||||||
|
submitExternalExtension(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.documentElement.appendChild(input);
|
||||||
|
input.click();
|
||||||
|
document.documentElement.removeChild(input);
|
||||||
|
}}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</CustomTooltip>
|
</CustomTooltip>
|
||||||
@@ -234,26 +248,6 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const FileInputComponent = useMemo(
|
|
||||||
() => (
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
ref={inputRef}
|
|
||||||
onChange={(e) => {
|
|
||||||
const file = e.target.files?.[0];
|
|
||||||
if (file) {
|
|
||||||
submitExternalExtension(file);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const isLoading = areServerSettingsLoading || areExtensionsLoading;
|
|
||||||
const error = serverSettingsError ?? extensionsError;
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <LoadingPlaceholder />;
|
return <LoadingPlaceholder />;
|
||||||
}
|
}
|
||||||
@@ -279,8 +273,6 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
|||||||
const showAddRepoInfo = !allExtensions?.length && !areReposDefined;
|
const showAddRepoInfo = !allExtensions?.length && !areReposDefined;
|
||||||
if (showAddRepoInfo) {
|
if (showAddRepoInfo) {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{FileInputComponent}
|
|
||||||
<Stack
|
<Stack
|
||||||
sx={{
|
sx={{
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -294,13 +286,11 @@ export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
|||||||
{t('settings.title')}
|
{t('settings.title')}
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{FileInputComponent}
|
|
||||||
<StyledGroupedVirtuoso
|
<StyledGroupedVirtuoso
|
||||||
heightToSubtract={tabsMenuHeight}
|
heightToSubtract={tabsMenuHeight}
|
||||||
overscan={window.innerHeight * 0.5}
|
overscan={window.innerHeight * 0.5}
|
||||||
|
|||||||
Reference in New Issue
Block a user