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:
parent
aaa116d218
commit
07bb315bb3
5 changed files with 105 additions and 48 deletions
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
40
src/hooks/useLocale.tsx
Normal 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
|
||||||
|
};
|
||||||
|
}
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue