Merge pull request #6933 from thornbill/item-count-widget

Add item count widget to dashboard
This commit is contained in:
Bill Thornton
2025-06-10 16:37:21 -04:00
committed by GitHub
10 changed files with 235 additions and 15 deletions
@@ -0,0 +1,33 @@
import type { Api } from '@jellyfin/sdk';
import type { LibraryApiGetItemCountsRequest } from '@jellyfin/sdk/lib/generated-client/api/library-api';
import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api';
import { queryOptions, useQuery } from '@tanstack/react-query';
import type { AxiosRequestConfig } from 'axios';
import { useApi } from 'hooks/useApi';
const fetchItemCounts = async (
api: Api,
params?: LibraryApiGetItemCountsRequest,
options?: AxiosRequestConfig
) => {
const response = await getLibraryApi(api)
.getItemCounts(params, options);
return response.data;
};
const getItemCountsQuery = (
api?: Api,
params?: LibraryApiGetItemCountsRequest
) => queryOptions({
queryKey: [ 'ItemCounts', params ],
queryFn: ({ signal }) => fetchItemCounts(api!, params, { signal }),
enabled: !!api
});
export const useItemCounts = (
params?: LibraryApiGetItemCountsRequest
) => {
const { api } = useApi();
return useQuery(getItemCountsQuery(api, params));
};
@@ -0,0 +1,71 @@
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import Skeleton from '@mui/material/Skeleton';
import Stack from '@mui/material/Stack';
import SvgIcon from '@mui/material/SvgIcon';
import Typography from '@mui/material/Typography';
import React, { type FC } from 'react';
import { useLocale } from 'hooks/useLocale';
import { toDecimalString } from 'utils/number';
interface Metric {
label: string
value?: number
}
interface MetricCardProps {
metrics: Metric[]
Icon: typeof SvgIcon
}
const MetricCard: FC<MetricCardProps> = ({
metrics,
Icon
}) => {
const { dateTimeLocale } = useLocale();
return (
<Card
sx={{
display: 'flex',
alignItems: 'center',
height: '100%'
}}
>
<Stack
direction='row'
sx={{
width: '100%',
padding: 2,
justifyContent: 'space-between',
alignItems: 'center'
}}
>
{metrics.map(({ label, value }) => (
<Box key={label}>
<Typography
variant='body2'
color='text.secondary'
>
{label}
</Typography>
<Typography
variant='h5'
component='div'
>
{typeof value !== 'undefined' ? (
toDecimalString(value, dateTimeLocale)
) : (
<Skeleton />
)}
</Typography>
</Box>
))}
<Icon fontSize='large' />
</Stack>
</Card>
);
};
export default MetricCard;