Migrate plugins catalog to React
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
export enum QueryKey {
|
||||
ConfigurationPages = 'ConfigurationPages',
|
||||
PackageInfo = 'PackageInfo',
|
||||
Packages = 'Packages',
|
||||
Plugins = 'Plugins',
|
||||
Repositories = 'Repositories'
|
||||
}
|
||||
|
||||
@@ -7,12 +7,24 @@ import type { AxiosRequestConfig } from 'axios';
|
||||
import { useApi } from 'hooks/useApi';
|
||||
|
||||
import { QueryKey } from './queryKey';
|
||||
import { queryClient } from 'utils/query/queryClient';
|
||||
import type { PackageInfo } from '@jellyfin/sdk/lib/generated-client/models/package-info';
|
||||
|
||||
const fetchPackageInfo = async (
|
||||
api: Api,
|
||||
params: PackageApiGetPackageInfoRequest,
|
||||
options?: AxiosRequestConfig
|
||||
) => {
|
||||
const packagesData = queryClient.getQueryData([ QueryKey.Packages ]) as PackageInfo[];
|
||||
if (packagesData && params.assemblyGuid) {
|
||||
// Use cached query to avoid re-fetching
|
||||
const pkg = packagesData.find(v => v.guid === params.assemblyGuid);
|
||||
|
||||
if (pkg) {
|
||||
return pkg;
|
||||
}
|
||||
}
|
||||
|
||||
const response = await getPackageApi(api)
|
||||
.getPackageInfo(params, options);
|
||||
return response.data;
|
||||
@@ -24,7 +36,7 @@ const getPackageInfoQuery = (
|
||||
) => queryOptions({
|
||||
// Don't retry since requests for plugins not available in repos fail
|
||||
retry: false,
|
||||
queryKey: [ QueryKey.PackageInfo, params?.name, params?.assemblyGuid ],
|
||||
queryKey: [ QueryKey.Packages, params?.name, params?.assemblyGuid ],
|
||||
queryFn: ({ signal }) => fetchPackageInfo(api!, params!, { signal }),
|
||||
enabled: !!params && !!api && !!params.name
|
||||
});
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { Api } from '@jellyfin/sdk';
|
||||
import { getPackageApi } from '@jellyfin/sdk/lib/utils/api/package-api';
|
||||
import { queryOptions, useQuery } from '@tanstack/react-query';
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
|
||||
import { useApi } from 'hooks/useApi';
|
||||
|
||||
import { QueryKey } from './queryKey';
|
||||
|
||||
const fetchPackages = async (
|
||||
api: Api,
|
||||
options?: AxiosRequestConfig
|
||||
) => {
|
||||
const response = await getPackageApi(api)
|
||||
.getPackages(options);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const getPackagesQuery = (
|
||||
api?: Api
|
||||
) => queryOptions({
|
||||
queryKey: [ QueryKey.Packages ],
|
||||
queryFn: ({ signal }) => fetchPackages(api!, { signal }),
|
||||
enabled: !!api,
|
||||
staleTime: 15 * 60 * 1000 // 15 minutes
|
||||
});
|
||||
|
||||
export const usePackages = () => {
|
||||
const { api } = useApi();
|
||||
return useQuery(getPackagesQuery(api));
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import type { PackageInfo } from '@jellyfin/sdk/lib/generated-client/models/package-info';
|
||||
import ExtensionIcon from '@mui/icons-material/Extension';
|
||||
import BaseCard from 'apps/dashboard/components/BaseCard';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
type IProps = {
|
||||
pkg: PackageInfo;
|
||||
};
|
||||
|
||||
const PackageCard = ({ pkg }: IProps) => {
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<BaseCard
|
||||
title={pkg.name}
|
||||
image={pkg.imageUrl}
|
||||
icon={<ExtensionIcon sx={{ width: 80, height: 80 }} />}
|
||||
to={{
|
||||
pathname: `/dashboard/plugins/${pkg.guid}`,
|
||||
search: `?name=${encodeURIComponent(pkg.name || '')}`,
|
||||
hash: location.hash
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PackageCard;
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useApi } from 'hooks/useApi';
|
||||
import type { PluginInfo } from '@jellyfin/sdk/lib/generated-client/models/plugin-info';
|
||||
@@ -37,14 +37,16 @@ const PluginCard = ({ plugin, configurationPage }: IProps) => {
|
||||
const [ isUninstallConfirmOpen, setIsUninstallConfirmOpen ] = useState(false);
|
||||
const { api } = useApi();
|
||||
|
||||
const navigateToPluginSettings = useCallback(() => {
|
||||
if (configurationPage) {
|
||||
navigate({
|
||||
pathname: '/configurationpage',
|
||||
search: `?name=${encodeURIComponent(configurationPage.Name || '')}`,
|
||||
hash: location.hash
|
||||
});
|
||||
const pluginPage = useMemo(() => (
|
||||
{
|
||||
pathname: '/configurationpage',
|
||||
search: `?name=${encodeURIComponent(configurationPage?.Name || '')}`,
|
||||
hash: location.hash
|
||||
}
|
||||
), [ location, configurationPage ]);
|
||||
|
||||
const navigateToPluginSettings = useCallback(() => {
|
||||
navigate(pluginPage);
|
||||
}, [ navigate, location, configurationPage ]);
|
||||
|
||||
const onEnablePlugin = useCallback(() => {
|
||||
@@ -105,12 +107,12 @@ const PluginCard = ({ plugin, configurationPage }: IProps) => {
|
||||
<BaseCard
|
||||
title={plugin.Name}
|
||||
secondaryTitle={plugin.Version}
|
||||
to={pluginPage}
|
||||
text={`${globalize.translate('LabelStatus')} ${plugin.Status}`}
|
||||
image={plugin.HasImage ? api?.getUri(`/Plugins/${plugin.Id}/${plugin.Version}/Image`) : null}
|
||||
icon={<ExtensionIcon sx={{ width: 80, height: 80 }} />}
|
||||
action={true}
|
||||
actionRef={actionRef}
|
||||
onClick={navigateToPluginSettings}
|
||||
onActionClick={onActionClick}
|
||||
/>
|
||||
<Menu
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { PackageInfo } from '@jellyfin/sdk/lib/generated-client/models/package-info';
|
||||
|
||||
const getPackageCategories = (packages?: PackageInfo[]) => {
|
||||
if (!packages) return [];
|
||||
|
||||
const categories: string[] = [];
|
||||
|
||||
for (const pkg of packages) {
|
||||
if (pkg.category && !categories.includes(pkg.category)) {
|
||||
categories.push(pkg.category);
|
||||
}
|
||||
}
|
||||
|
||||
return categories.sort((a, b) => a.localeCompare(b));
|
||||
};
|
||||
|
||||
export default getPackageCategories;
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { PackageInfo } from '@jellyfin/sdk/lib/generated-client/models/package-info';
|
||||
|
||||
const getPackagesByCategory = (packages: PackageInfo[] | undefined, category: string) => {
|
||||
if (!packages) return [];
|
||||
|
||||
return packages.filter(pkg => pkg.category == category).sort((a, b) => {
|
||||
if (a.name && b.name) {
|
||||
return a.name?.localeCompare(b.name);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default getPackagesByCategory;
|
||||
Reference in New Issue
Block a user