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

Merge pull request #6526 from thornbill/api-keys-table-page

Refactor api keys to use TablePage component
This commit is contained in:
Bill Thornton 2025-02-17 10:42:05 -05:00 committed by GitHub
commit a367e61a8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 58 additions and 77 deletions

View file

@ -1,4 +1,5 @@
import Box from '@mui/material/Box/Box'; import Box from '@mui/material/Box/Box';
import Stack from '@mui/material/Stack/Stack';
import Typography from '@mui/material/Typography/Typography'; import Typography from '@mui/material/Typography/Typography';
import { type MRT_RowData, type MRT_TableInstance, MaterialReactTable } from 'material-react-table'; import { type MRT_RowData, type MRT_TableInstance, MaterialReactTable } from 'material-react-table';
import React from 'react'; import React from 'react';
@ -7,6 +8,7 @@ import Page, { type PageProps } from 'components/Page';
interface TablePageProps<T extends MRT_RowData> extends PageProps { interface TablePageProps<T extends MRT_RowData> extends PageProps {
title: string title: string
subtitle?: string
table: MRT_TableInstance<T> table: MRT_TableInstance<T>
} }
@ -27,6 +29,7 @@ export const DEFAULT_TABLE_OPTIONS = {
const TablePage = <T extends MRT_RowData>({ const TablePage = <T extends MRT_RowData>({
title, title,
subtitle,
table, table,
children, children,
...pageProps ...pageProps
@ -44,7 +47,8 @@ const TablePage = <T extends MRT_RowData>({
height: '100%' height: '100%'
}} }}
> >
<Box <Stack
spacing={2}
sx={{ sx={{
marginBottom: 1 marginBottom: 1
}} }}
@ -52,7 +56,12 @@ const TablePage = <T extends MRT_RowData>({
<Typography variant='h2'> <Typography variant='h2'>
{title} {title}
</Typography> </Typography>
</Box> {subtitle && (
<Typography>
{subtitle}
</Typography>
)}
</Stack>
<MaterialReactTable table={table} /> <MaterialReactTable table={table} />
</Box> </Box>
{children} {children}

View file

@ -40,7 +40,7 @@ const getUserCell = (users: UsersRecords) => function UserCell({ row }: Activity
); );
}; };
const Activity = () => { export const Component = () => {
const [ searchParams, setSearchParams ] = useSearchParams(); const [ searchParams, setSearchParams ] = useSearchParams();
const [ activityView, setActivityView ] = useState( const [ activityView, setActivityView ] = useState(
@ -61,7 +61,13 @@ const Activity = () => {
hasUserId: activityView !== ActivityView.All ? activityView === ActivityView.User : undefined hasUserId: activityView !== ActivityView.All ? activityView === ActivityView.User : undefined
}), [activityView, pagination.pageIndex, pagination.pageSize]); }), [activityView, pagination.pageIndex, pagination.pageSize]);
const { data: logEntries, isLoading: isLogEntriesLoading } = useLogEntries(activityParams); const { data, isLoading: isLogEntriesLoading } = useLogEntries(activityParams);
const logEntries = useMemo(() => (
data?.Items || []
), [ data ]);
const rowCount = useMemo(() => (
data?.TotalRecordCount || 0
), [ data ]);
const isLoading = isUsersLoading || isLogEntriesLoading; const isLoading = isUsersLoading || isLogEntriesLoading;
@ -154,7 +160,7 @@ const Activity = () => {
...DEFAULT_TABLE_OPTIONS, ...DEFAULT_TABLE_OPTIONS,
columns, columns,
data: logEntries?.Items || [], data: logEntries,
// State // State
initialState: { initialState: {
@ -168,7 +174,7 @@ const Activity = () => {
// Server pagination // Server pagination
manualPagination: true, manualPagination: true,
onPaginationChange: setPagination, onPaginationChange: setPagination,
rowCount: logEntries?.TotalRecordCount || 0, rowCount,
// Custom toolbar contents // Custom toolbar contents
renderTopToolbarCustomActions: () => ( renderTopToolbarCustomActions: () => (
@ -201,4 +207,4 @@ const Activity = () => {
); );
}; };
export default Activity; Component.displayName = 'ActivityPage';

View file

@ -1,28 +1,30 @@
import parseISO from 'date-fns/parseISO';
import DateTimeCell from 'apps/dashboard/components/table/DateTimeCell';
import Page from 'components/Page';
import { useApi } from 'hooks/useApi';
import globalize from 'lib/globalize';
import React, { useCallback, useMemo } from 'react';
import type { AuthenticationInfo } from '@jellyfin/sdk/lib/generated-client/models/authentication-info'; import type { AuthenticationInfo } from '@jellyfin/sdk/lib/generated-client/models/authentication-info';
import confirm from 'components/confirm/confirm';
import { useApiKeys } from 'apps/dashboard/features/keys/api/useApiKeys';
import { useRevokeKey } from 'apps/dashboard/features/keys/api/useRevokeKey';
import { useCreateKey } from 'apps/dashboard/features/keys/api/useCreateKey';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';
import { MaterialReactTable, MRT_ColumnDef, useMaterialReactTable } from 'material-react-table';
import DeleteIcon from '@mui/icons-material/Delete';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import DeleteIcon from '@mui/icons-material/Delete';
import parseISO from 'date-fns/parseISO';
import { type MRT_ColumnDef, useMaterialReactTable } from 'material-react-table';
import React, { useCallback, useMemo } from 'react';
const ApiKeys = () => { import DateTimeCell from 'apps/dashboard/components/table/DateTimeCell';
import TablePage, { DEFAULT_TABLE_OPTIONS } from 'apps/dashboard/components/table/TablePage';
import { useApiKeys } from 'apps/dashboard/features/keys/api/useApiKeys';
import { useRevokeKey } from 'apps/dashboard/features/keys/api/useRevokeKey';
import { useCreateKey } from 'apps/dashboard/features/keys/api/useCreateKey';
import confirm from 'components/confirm/confirm';
import prompt from 'components/prompt/prompt';
import { useApi } from 'hooks/useApi';
import globalize from 'lib/globalize';
export const Component = () => {
const { api } = useApi(); const { api } = useApi();
const { data: keys, isLoading } = useApiKeys(); const { data, isLoading } = useApiKeys();
const keys = useMemo(() => (
data?.Items || []
), [ data ]);
const revokeKey = useRevokeKey(); const revokeKey = useRevokeKey();
const createKey = useCreateKey(); const createKey = useCreateKey();
@ -48,26 +50,15 @@ const ApiKeys = () => {
], []); ], []);
const table = useMaterialReactTable({ const table = useMaterialReactTable({
...DEFAULT_TABLE_OPTIONS,
columns, columns,
data: keys?.Items || [], data: keys,
state: { state: {
isLoading isLoading
}, },
rowCount: keys?.TotalRecordCount || 0,
enableColumnPinning: true,
enableColumnResizing: true,
enableStickyFooter: true,
enableStickyHeader: true,
muiTableContainerProps: {
sx: {
maxHeight: 'calc(100% - 7rem)' // 2 x 3.5rem for header and footer
}
},
// Enable (delete) row actions // Enable (delete) row actions
enableRowActions: true, enableRowActions: true,
positionActionsColumn: 'last', positionActionsColumn: 'last',
@ -119,53 +110,28 @@ const ApiKeys = () => {
const showNewKeyPopup = useCallback(() => { const showNewKeyPopup = useCallback(() => {
if (!api) return; if (!api) return;
import('../../../../components/prompt/prompt').then(({ default: prompt }) => { prompt({
prompt({ title: globalize.translate('HeaderNewApiKey'),
title: globalize.translate('HeaderNewApiKey'), label: globalize.translate('LabelAppName'),
label: globalize.translate('LabelAppName'), description: globalize.translate('LabelAppNameExample')
description: globalize.translate('LabelAppNameExample') }).then((value) => {
}).then((value) => { createKey.mutate({
createKey.mutate({ app: value
app: value
});
}).catch(() => {
// popup closed
}); });
}).catch(err => { }).catch(() => {
console.error('[apikeys] failed to load api key popup', err); // popup closed
}); });
}, [api, createKey]); }, [api, createKey]);
return ( return (
<Page <TablePage
id='apiKeysPage' id='apiKeysPage'
title={globalize.translate('HeaderApiKeys')} title={globalize.translate('HeaderApiKeys')}
subtitle={globalize.translate('HeaderApiKeysHelp')}
className='mainAnimatedPage type-interior' className='mainAnimatedPage type-interior'
> table={table}
<Box />
className='content-primary'
sx={{
display: 'flex',
flexDirection: 'column',
height: '100%'
}}
>
<Box
sx={{
marginBottom: 1
}}
>
<Stack spacing={2}>
<Typography variant='h2'>
{globalize.translate('HeaderApiKeys')}
</Typography>
<Typography>{globalize.translate('HeaderApiKeysHelp')}</Typography>
</Stack>
</Box>
<MaterialReactTable table={table} />
</Box>
</Page>
); );
}; };
export default ApiKeys; Component.displayName = 'ApiKeysPage';