Merge pull request #6925 from viown/react-plugins-repositories

Migrate plugin repositories to React
This commit is contained in:
Bill Thornton
2025-06-10 18:27:50 -04:00
committed by GitHub
11 changed files with 329 additions and 217 deletions
@@ -19,6 +19,7 @@ export const ASYNC_ADMIN_ROUTES: AsyncRoute[] = [
{ path: 'playback/trickplay', type: AppType.Dashboard },
{ path: 'plugins', type: AppType.Dashboard },
{ path: 'plugins/:pluginId', page: 'plugins/plugin', type: AppType.Dashboard },
{ path: 'plugins/repositories', type: AppType.Dashboard },
{ path: 'tasks', type: AppType.Dashboard },
{ path: 'tasks/:id', page: 'tasks/task', type: AppType.Dashboard },
{ path: 'users', type: AppType.Dashboard },
@@ -30,13 +30,6 @@ export const LEGACY_ADMIN_ROUTES: LegacyRoute[] = [
controller: 'plugins/available/index',
view: 'plugins/available/index.html'
}
}, {
path: 'plugins/repositories',
pageProps: {
appType: AppType.Dashboard,
controller: 'plugins/repositories/index',
view: 'plugins/repositories/index.html'
}
}, {
path: 'livetv/guide',
pageProps: {
@@ -0,0 +1,107 @@
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import AddIcon from '@mui/icons-material/Add';
import Page from 'components/Page';
import globalize from 'lib/globalize';
import React, { useCallback, useState } from 'react';
import Stack from '@mui/material/Stack';
import { useRepositories } from 'apps/dashboard/features/plugins/api/useRepositories';
import Loading from 'components/loading/LoadingComponent';
import Alert from '@mui/material/Alert';
import List from '@mui/material/List';
import RepositoryListItem from 'apps/dashboard/features/plugins/components/RepositoryListItem';
import type { RepositoryInfo } from '@jellyfin/sdk/lib/generated-client/models/repository-info';
import { useSetRepositories } from 'apps/dashboard/features/plugins/api/useSetRepositories';
import NewRepositoryForm from 'apps/dashboard/features/plugins/components/NewRepositoryForm';
export const Component = () => {
const { data: repositories, isPending, isError } = useRepositories();
const [ isRepositoryFormOpen, setIsRepositoryFormOpen ] = useState(false);
const setRepositories = useSetRepositories();
const onDelete = useCallback((repository: RepositoryInfo) => {
if (repositories) {
setRepositories.mutate({
repositoryInfo: repositories.filter(currentRepo => currentRepo.Url !== repository.Url)
});
}
}, [ repositories, setRepositories ]);
const onRepositoryAdd = useCallback((repository: RepositoryInfo) => {
if (repositories) {
setRepositories.mutate({
repositoryInfo: [
...repositories,
repository
]
}, {
onSettled: () => {
setIsRepositoryFormOpen(false);
}
});
}
}, [ repositories, setRepositories ]);
const openRepositoryForm = useCallback(() => {
setIsRepositoryFormOpen(true);
}, []);
const onRepositoryFormClose = useCallback(() => {
setIsRepositoryFormOpen(false);
}, []);
if (isPending) {
return <Loading />;
}
return (
<Page
id='repositories'
title={globalize.translate('TabRepositories')}
className='type-interior mainAnimatedPage'
>
<NewRepositoryForm
open={isRepositoryFormOpen}
onClose={onRepositoryFormClose}
onAdd={onRepositoryAdd}
/>
<Box className='content-primary'>
{isError ? (
<Alert severity='error'>{globalize.translate('RepositoriesPageLoadError')}</Alert>
) : (
<Stack spacing={3}>
<Typography variant='h1'>{globalize.translate('TabRepositories')}</Typography>
<Button
sx={{ alignSelf: 'flex-start' }}
startIcon={<AddIcon />}
onClick={openRepositoryForm}
>
{globalize.translate('HeaderNewRepository')}
</Button>
{repositories.length > 0 ? (
<List sx={{ bgcolor: 'background.paper' }}>
{repositories.map(repository => {
return <RepositoryListItem
key={repository.Url}
repository={repository}
onDelete={onDelete}
/>;
})}
</List>
) : (
<Stack alignSelf='center' alignItems='center' maxWidth={'500px'} spacing={2}>
<Typography variant='h2'>{globalize.translate('MessageNoRepositories')}</Typography>
<Typography textAlign='center'>{globalize.translate('MessageAddRepository')}</Typography>
</Stack>
)}
</Stack>
)}
</Box>
</Page>
);
};
Component.displayName = 'PluginRepositoriesPage';