Add categories for built-in plugins
This commit is contained in:
@@ -3,12 +3,14 @@ import { useMemo } from 'react';
|
||||
|
||||
import { useApi } from 'hooks/useApi';
|
||||
|
||||
import { useConfigurationPages } from './useConfigurationPages';
|
||||
import { usePlugins } from './usePlugins';
|
||||
import { PluginCategory } from '../constants/pluginCategory';
|
||||
import type { PluginDetails } from '../types/PluginDetails';
|
||||
|
||||
import { findBestConfigurationPage } from './configurationPage';
|
||||
import { findBestPluginInfo } from './pluginInfo';
|
||||
import { useConfigurationPages } from './useConfigurationPages';
|
||||
import { usePackages } from './usePackages';
|
||||
import { usePlugins } from './usePlugins';
|
||||
|
||||
export const usePluginDetails = () => {
|
||||
const { api } = useApi();
|
||||
@@ -64,9 +66,25 @@ export const usePluginDetails = () => {
|
||||
imageUrl = api?.getUri(`/Plugins/${pluginInfo.Id}/${pluginInfo.Version}/Image`);
|
||||
}
|
||||
|
||||
let category = packageInfo?.category;
|
||||
if (!packageInfo) {
|
||||
switch (id) {
|
||||
case 'a629c0dafac54c7e931a7174223f14c8': // AudioDB
|
||||
case '8c95c4d2e50c4fb0a4f36c06ff0f9a1a': // MusicBrainz
|
||||
category = PluginCategory.Music;
|
||||
break;
|
||||
case 'a628c0dafac54c7e9d1a7134223f14c8': // OMDb
|
||||
case 'b8715ed16c4745289ad3f72deb539cd4': // TMDb
|
||||
category = PluginCategory.MoviesAndShows;
|
||||
break;
|
||||
case '872a78491171458da6fb3de3d442ad30': // Studio Images
|
||||
category = PluginCategory.General;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
canUninstall: !!pluginInfo?.CanUninstall,
|
||||
category: packageInfo?.category,
|
||||
category,
|
||||
description: pluginInfo?.Description || packageInfo?.description || packageInfo?.overview,
|
||||
id,
|
||||
imageUrl: imageUrl || packageInfo?.imageUrl || undefined,
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { PluginCategory } from './pluginCategory';
|
||||
|
||||
/** A mapping of category names used by the plugin repository to translation keys. */
|
||||
export const CATEGORY_LABELS: Record<string, string> = {
|
||||
Administration: 'HeaderAdmin',
|
||||
General: 'General',
|
||||
Anime: 'Anime',
|
||||
// Authentication: 'LabelAuthProvider', // Legacy
|
||||
Books: 'Books',
|
||||
// Channel: 'Channels', // Unused?
|
||||
LiveTV: 'LiveTV',
|
||||
// Metadata: 'LabelMetadata', // Legacy
|
||||
MoviesAndShows: 'MoviesAndShows',
|
||||
Music: 'TabMusic',
|
||||
Subtitles: 'Subtitles',
|
||||
Other: 'Other'
|
||||
export const CATEGORY_LABELS: Record<PluginCategory, string> = {
|
||||
[PluginCategory.Administration]: 'HeaderAdmin',
|
||||
[PluginCategory.General]: 'General',
|
||||
[PluginCategory.Anime]: 'Anime',
|
||||
[PluginCategory.Books]: 'Books',
|
||||
[PluginCategory.LiveTV]: 'LiveTV',
|
||||
[PluginCategory.MoviesAndShows]: 'MoviesAndShows',
|
||||
[PluginCategory.Music]: 'TabMusic',
|
||||
[PluginCategory.Subtitles]: 'Subtitles',
|
||||
[PluginCategory.Other]: 'Other'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/** Supported plugin category values. */
|
||||
export enum PluginCategory {
|
||||
Administration = 'Administration',
|
||||
General = 'General',
|
||||
Anime = 'Anime',
|
||||
Books = 'Books',
|
||||
LiveTV = 'LiveTV',
|
||||
MoviesAndShows = 'MoviesAndShows',
|
||||
Music = 'Music',
|
||||
Subtitles = 'Subtitles',
|
||||
Other = 'Other'
|
||||
}
|
||||
@@ -1,20 +1,22 @@
|
||||
import Settings from '@mui/icons-material/Settings';
|
||||
import Box from '@mui/material/Box';
|
||||
import Grid from '@mui/material/Grid2';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { usePackages } from 'apps/dashboard/features/plugins/api/usePackages';
|
||||
import PackageCard from 'apps/dashboard/features/plugins/components/PackageCard';
|
||||
import { PluginCategory } from 'apps/dashboard/features/plugins/constants/pluginCategory';
|
||||
import { CATEGORY_LABELS } from 'apps/dashboard/features/plugins/constants/categoryLabels';
|
||||
import getPackageCategories from 'apps/dashboard/features/plugins/utils/getPackageCategories';
|
||||
import getPackagesByCategory from 'apps/dashboard/features/plugins/utils/getPackagesByCategory';
|
||||
import Loading from 'components/loading/LoadingComponent';
|
||||
import Page from 'components/Page';
|
||||
import globalize from 'lib/globalize';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { usePackages } from 'apps/dashboard/features/plugins/api/usePackages';
|
||||
import Loading from 'components/loading/LoadingComponent';
|
||||
import getPackageCategories from 'apps/dashboard/features/plugins/utils/getPackageCategories';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import getPackagesByCategory from 'apps/dashboard/features/plugins/utils/getPackagesByCategory';
|
||||
import PackageCard from 'apps/dashboard/features/plugins/components/PackageCard';
|
||||
import Grid from '@mui/material/Grid2';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Settings from '@mui/icons-material/Settings';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { CATEGORY_LABELS } from 'apps/dashboard/features/plugins/constants/categoryLabels';
|
||||
|
||||
export const Component = () => {
|
||||
const { data: packages, isPending: isPackagesPending } = usePackages();
|
||||
@@ -31,7 +33,7 @@ export const Component = () => {
|
||||
}, []);
|
||||
|
||||
const getCategoryLabel = (category: string) => {
|
||||
const categoryKey = category.replace(/\s/g, '');
|
||||
const categoryKey = category.replace(/\s/g, '') as PluginCategory;
|
||||
|
||||
if (CATEGORY_LABELS[categoryKey]) {
|
||||
return globalize.translate(CATEGORY_LABELS[categoryKey]);
|
||||
|
||||
@@ -1,34 +1,42 @@
|
||||
import Settings from '@mui/icons-material/Settings';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import Box from '@mui/material/Box';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Grid from '@mui/material/Grid2';
|
||||
import IconButton from '@mui/material/IconButton/IconButton';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import SearchInput from 'apps/dashboard/components/SearchInput';
|
||||
import { usePluginDetails } from 'apps/dashboard/features/plugins/api/usePluginDetails';
|
||||
import PluginCard from 'apps/dashboard/features/plugins/components/PluginCard';
|
||||
import { PluginCategory } from 'apps/dashboard/features/plugins/constants/pluginCategory';
|
||||
import { CATEGORY_LABELS } from 'apps/dashboard/features/plugins/constants/categoryLabels';
|
||||
import Loading from 'components/loading/LoadingComponent';
|
||||
import Page from 'components/Page';
|
||||
import globalize from 'lib/globalize';
|
||||
import { usePluginDetails } from 'apps/dashboard/features/plugins/api/usePluginDetails';
|
||||
import { Link } from 'react-router-dom';
|
||||
import IconButton from '@mui/material/IconButton/IconButton';
|
||||
import Settings from '@mui/icons-material/Settings';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import { CATEGORY_LABELS } from 'apps/dashboard/features/plugins/constants/categoryLabels';
|
||||
import SearchInput from 'apps/dashboard/components/SearchInput';
|
||||
|
||||
/**
|
||||
* The list of primary/main categories.
|
||||
* Any category not in this list will be added to the "other" category.
|
||||
*/
|
||||
const MAIN_CATEGORIES = [
|
||||
'administration',
|
||||
'general',
|
||||
'anime',
|
||||
'books',
|
||||
'livetv',
|
||||
'moviesandshows',
|
||||
'music',
|
||||
'subtitles'
|
||||
PluginCategory.Administration.toLowerCase(),
|
||||
PluginCategory.General.toLowerCase(),
|
||||
PluginCategory.Anime.toLowerCase(),
|
||||
PluginCategory.Books.toLowerCase(),
|
||||
PluginCategory.LiveTV.toLowerCase(),
|
||||
PluginCategory.MoviesAndShows.toLowerCase(),
|
||||
PluginCategory.Music.toLowerCase(),
|
||||
PluginCategory.Subtitles.toLowerCase()
|
||||
];
|
||||
|
||||
/** The installed meta category. */
|
||||
const INSTALLED_CATEGORY = 'installed';
|
||||
|
||||
export const Component = () => {
|
||||
const {
|
||||
data: pluginDetails,
|
||||
@@ -47,18 +55,19 @@ export const Component = () => {
|
||||
let filtered = pluginDetails;
|
||||
|
||||
if (category) {
|
||||
if (category === 'installed') {
|
||||
if (category === INSTALLED_CATEGORY) {
|
||||
// Installed plugins will have a status
|
||||
filtered = filtered.filter(p => p.status);
|
||||
} else if (category === 'other') {
|
||||
} else if (category === PluginCategory.Other.toLowerCase()) {
|
||||
filtered = filtered.filter(p => (
|
||||
p.category && !MAIN_CATEGORIES.includes(p.category.toLocaleLowerCase())
|
||||
p.category && !MAIN_CATEGORIES.includes(p.category.toLowerCase())
|
||||
));
|
||||
} else {
|
||||
filtered = filtered.filter(p => p.category?.toLocaleLowerCase() === category);
|
||||
filtered = filtered.filter(p => p.category?.toLowerCase() === category);
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
.filter(i => i.name?.toLocaleLowerCase().includes(searchQuery.toLocaleLowerCase()));
|
||||
.filter(i => i.name?.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
@@ -147,21 +156,21 @@ export const Component = () => {
|
||||
/>
|
||||
|
||||
<Chip
|
||||
color={category === 'installed' ? 'primary' : undefined}
|
||||
color={category === INSTALLED_CATEGORY ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setCategory('installed')}
|
||||
onClick={() => setCategory(INSTALLED_CATEGORY)}
|
||||
label={globalize.translate('LabelInstalled')}
|
||||
/>
|
||||
|
||||
<Divider orientation='vertical' flexItem />
|
||||
|
||||
{Object.keys(CATEGORY_LABELS).map(c => (
|
||||
{Object.values(PluginCategory).map(c => (
|
||||
<Chip
|
||||
key={c}
|
||||
color={category === c.toLocaleLowerCase() ? 'primary' : undefined}
|
||||
color={category === c.toLowerCase() ? 'primary' : undefined}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={() => setCategory(c.toLocaleLowerCase())}
|
||||
label={globalize.translate(CATEGORY_LABELS[c])}
|
||||
onClick={() => setCategory(c.toLowerCase())}
|
||||
label={globalize.translate(CATEGORY_LABELS[c as PluginCategory])}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user