1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Add date filter to activity table

This commit is contained in:
Bill Thornton 2024-08-29 01:59:33 -04:00
parent aaa116d218
commit 07bb315bb3
5 changed files with 105 additions and 48 deletions

View file

@ -2,6 +2,8 @@ import AppBar from '@mui/material/AppBar';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import { type Theme } from '@mui/material/styles'; import { type Theme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery'; import useMediaQuery from '@mui/material/useMediaQuery';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import React, { FC, useCallback, useEffect, useState } from 'react'; import React, { FC, useCallback, useEffect, useState } from 'react';
import { Outlet, useLocation } from 'react-router-dom'; import { Outlet, useLocation } from 'react-router-dom';
@ -10,6 +12,7 @@ import AppToolbar from 'components/toolbar/AppToolbar';
import ElevationScroll from 'components/ElevationScroll'; import ElevationScroll from 'components/ElevationScroll';
import { DRAWER_WIDTH } from 'components/ResponsiveDrawer'; import { DRAWER_WIDTH } from 'components/ResponsiveDrawer';
import { useApi } from 'hooks/useApi'; import { useApi } from 'hooks/useApi';
import { useLocale } from 'hooks/useLocale';
import AppTabs from './components/AppTabs'; import AppTabs from './components/AppTabs';
import AppDrawer from './components/drawer/AppDrawer'; import AppDrawer from './components/drawer/AppDrawer';
@ -23,6 +26,7 @@ export const Component: FC = () => {
const [ isDrawerActive, setIsDrawerActive ] = useState(false); const [ isDrawerActive, setIsDrawerActive ] = useState(false);
const location = useLocation(); const location = useLocation();
const { user } = useApi(); const { user } = useApi();
const { dateFnsLocale } = useLocale();
const isMediumScreen = useMediaQuery((t: Theme) => t.breakpoints.up('md')); const isMediumScreen = useMediaQuery((t: Theme) => t.breakpoints.up('md'));
const isDrawerAvailable = Boolean(user) const isDrawerAvailable = Boolean(user)
@ -43,52 +47,54 @@ export const Component: FC = () => {
}, []); }, []);
return ( return (
<Box sx={{ display: 'flex' }}> <LocalizationProvider dateAdapter={AdapterDateFns} adapterLocale={dateFnsLocale}>
<ElevationScroll elevate={false}> <Box sx={{ display: 'flex' }}>
<AppBar <ElevationScroll elevate={false}>
position='fixed' <AppBar
position='fixed'
sx={{
width: {
xs: '100%',
md: isDrawerAvailable ? `calc(100% - ${DRAWER_WIDTH}px)` : '100%'
},
ml: {
xs: 0,
md: isDrawerAvailable ? DRAWER_WIDTH : 0
}
}}
>
<AppToolbar
isDrawerAvailable={!isMediumScreen && isDrawerAvailable}
isDrawerOpen={isDrawerOpen}
onDrawerButtonClick={onToggleDrawer}
>
<AppTabs isDrawerOpen={isDrawerOpen} />
</AppToolbar>
</AppBar>
</ElevationScroll>
{
isDrawerAvailable && (
<AppDrawer
open={isDrawerOpen}
onClose={onToggleDrawer}
onOpen={onToggleDrawer}
/>
)
}
<Box
component='main'
sx={{ sx={{
width: { width: '100%',
xs: '100%', flexGrow: 1
md: isDrawerAvailable ? `calc(100% - ${DRAWER_WIDTH}px)` : '100%'
},
ml: {
xs: 0,
md: isDrawerAvailable ? DRAWER_WIDTH : 0
}
}} }}
> >
<AppToolbar <AppBody>
isDrawerAvailable={!isMediumScreen && isDrawerAvailable} <Outlet />
isDrawerOpen={isDrawerOpen} </AppBody>
onDrawerButtonClick={onToggleDrawer} </Box>
>
<AppTabs isDrawerOpen={isDrawerOpen} />
</AppToolbar>
</AppBar>
</ElevationScroll>
{
isDrawerAvailable && (
<AppDrawer
open={isDrawerOpen}
onClose={onToggleDrawer}
onOpen={onToggleDrawer}
/>
)
}
<Box
component='main'
sx={{
width: '100%',
flexGrow: 1
}}
>
<AppBody>
<Outlet />
</AppBody>
</Box> </Box>
</Box> </LocalizationProvider>
); );
}; };

View file

@ -101,7 +101,8 @@ const Activity = () => {
accessorFn: row => parseISO8601Date(row.Date), accessorFn: row => parseISO8601Date(row.Date),
header: globalize.translate('LabelTime'), header: globalize.translate('LabelTime'),
size: 160, size: 160,
Cell: ({ cell }) => toLocaleString(cell.getValue<Date>()) Cell: ({ cell }) => toLocaleString(cell.getValue<Date>()),
filterVariant: 'datetime-range'
}, },
{ {
accessorKey: 'Severity', accessorKey: 'Severity',

40
src/hooks/useLocale.tsx Normal file
View file

@ -0,0 +1,40 @@
import type { Locale } from 'date-fns';
import enUS from 'date-fns/locale/en-US';
import { useEffect, useMemo, useState } from 'react';
import { getDefaultLanguage, normalizeLocaleName } from 'lib/globalize';
import { fetchLocale, normalizeLocale } from 'utils/dateFnsLocale';
import { useUserSettings } from './useUserSettings';
export function useLocale() {
const { dateTimeLocale: dateTimeSetting, language } = useUserSettings();
const [ dateFnsLocale, setDateFnsLocale ] = useState<Locale>(enUS);
const locale = useMemo(() => (
normalizeLocaleName(language || getDefaultLanguage())
), [ language ]);
const dateTimeLocale = useMemo(() => (
dateTimeSetting ? normalizeLocaleName(dateTimeSetting) : locale
), [ dateTimeSetting, locale ]);
useEffect(() => {
const fetchDateFnsLocale = async () => {
try {
const dfLocale = await fetchLocale(normalizeLocale(dateTimeLocale));
setDateFnsLocale(dfLocale);
} catch (err) {
console.warn('[useLocale] failed to fetch dateFns locale', err);
}
};
void fetchDateFnsLocale();
}, [ dateTimeLocale ]);
return {
locale,
dateTimeLocale,
dateFnsLocale
};
}

View file

@ -25,7 +25,7 @@ export function getCurrentDateTimeLocale() {
return currentDateTimeCulture; return currentDateTimeCulture;
} }
function getDefaultLanguage() { export function getDefaultLanguage() {
const culture = document.documentElement.getAttribute('data-culture'); const culture = document.documentElement.getAttribute('data-culture');
if (culture) { if (culture) {
return culture; return culture;
@ -127,7 +127,7 @@ function ensureTranslation(translationInfo, culture) {
}); });
} }
function normalizeLocaleName(culture) { export function normalizeLocaleName(culture) {
return culture.replace('_', '-').toLowerCase(); return culture.replace('_', '-').toLowerCase();
} }

View file

@ -67,11 +67,21 @@ const DEFAULT_LOCALE = 'en-US';
let localeString = DEFAULT_LOCALE; let localeString = DEFAULT_LOCALE;
let locale = enUS; let locale = enUS;
export function fetchLocale(localeName: string) {
return import(`date-fns/locale/${localeName}/index.js`);
}
export function normalizeLocale(localeName: string) {
return LOCALE_MAP[localeName]
|| LOCALE_MAP[localeName.replace(/-.*/, '')]
|| DEFAULT_LOCALE;
}
export async function updateLocale(newLocale: string) { export async function updateLocale(newLocale: string) {
console.debug('[dateFnsLocale] updating date-fns locale', newLocale); console.debug('[dateFnsLocale] updating date-fns locale', newLocale);
localeString = LOCALE_MAP[newLocale] || LOCALE_MAP[newLocale.replace(/-.*/, '')] || DEFAULT_LOCALE; localeString = normalizeLocale(newLocale);
console.debug('[dateFnsLocale] mapped to date-fns locale', localeString); console.debug('[dateFnsLocale] mapped to date-fns locale', localeString);
locale = await import(`date-fns/locale/${localeString}/index.js`); locale = await fetchLocale(localeString);
} }
export function getLocale() { export function getLocale() {