From cb906678e68957d9d9368799867e227f17978ed1 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 27 Aug 2024 10:49:15 -0400 Subject: [PATCH] Refactor cell components --- .../features/activity/api}/useLogEntries.tsx | 2 +- .../activity/components/ActionsCell.tsx | 22 ++++++ .../activity/components/LogLevelCell.tsx | 13 ++++ .../activity/components}/LogLevelChip.tsx | 0 .../activity/components}/OverviewCell.tsx | 8 +- .../activity/components/UserAvatarButton.tsx | 27 +++++++ .../activity/types/ActivityLogEntryCell.ts | 7 ++ src/apps/dashboard/routes/activity.tsx | 76 +++++++------------ 8 files changed, 103 insertions(+), 52 deletions(-) rename src/{hooks => apps/dashboard/features/activity/api}/useLogEntries.tsx (96%) create mode 100644 src/apps/dashboard/features/activity/components/ActionsCell.tsx create mode 100644 src/apps/dashboard/features/activity/components/LogLevelCell.tsx rename src/apps/dashboard/{components/activityTable => features/activity/components}/LogLevelChip.tsx (100%) rename src/apps/dashboard/{components/activityTable => features/activity/components}/OverviewCell.tsx (87%) create mode 100644 src/apps/dashboard/features/activity/components/UserAvatarButton.tsx create mode 100644 src/apps/dashboard/features/activity/types/ActivityLogEntryCell.ts diff --git a/src/hooks/useLogEntries.tsx b/src/apps/dashboard/features/activity/api/useLogEntries.tsx similarity index 96% rename from src/hooks/useLogEntries.tsx rename to src/apps/dashboard/features/activity/api/useLogEntries.tsx index 9f548087bf..b0f1be5233 100644 --- a/src/hooks/useLogEntries.tsx +++ b/src/apps/dashboard/features/activity/api/useLogEntries.tsx @@ -4,7 +4,7 @@ import type { Api } from '@jellyfin/sdk'; import { getActivityLogApi } from '@jellyfin/sdk/lib/utils/api/activity-log-api'; import { useQuery } from '@tanstack/react-query'; -import { useApi } from './useApi'; +import { useApi } from 'hooks/useApi'; const fetchLogEntries = async ( api?: Api, diff --git a/src/apps/dashboard/features/activity/components/ActionsCell.tsx b/src/apps/dashboard/features/activity/components/ActionsCell.tsx new file mode 100644 index 0000000000..0f00613270 --- /dev/null +++ b/src/apps/dashboard/features/activity/components/ActionsCell.tsx @@ -0,0 +1,22 @@ +import IconButton from '@mui/material/IconButton/IconButton'; +import PermMedia from '@mui/icons-material/PermMedia'; +import React, { type FC } from 'react'; +import { Link } from 'react-router-dom'; + +import type { ActivityLogEntryCell } from 'apps/dashboard/features/activity/types/ActivityLogEntryCell'; +import globalize from 'lib/globalize'; + +const ActionsCell: FC = ({ row }) => ( + row.original.ItemId ? ( + + + + ) : undefined +); + +export default ActionsCell; diff --git a/src/apps/dashboard/features/activity/components/LogLevelCell.tsx b/src/apps/dashboard/features/activity/components/LogLevelCell.tsx new file mode 100644 index 0000000000..b884581c4e --- /dev/null +++ b/src/apps/dashboard/features/activity/components/LogLevelCell.tsx @@ -0,0 +1,13 @@ +import type { LogLevel } from '@jellyfin/sdk/lib/generated-client/models/log-level'; +import React, { type FC } from 'react'; + +import { ActivityLogEntryCell } from '../types/ActivityLogEntryCell'; +import LogLevelChip from './LogLevelChip'; + +const LogLevelCell: FC = ({ cell }) => ( + cell.getValue() ? ( + ()} /> + ) : undefined +); + +export default LogLevelCell; diff --git a/src/apps/dashboard/components/activityTable/LogLevelChip.tsx b/src/apps/dashboard/features/activity/components/LogLevelChip.tsx similarity index 100% rename from src/apps/dashboard/components/activityTable/LogLevelChip.tsx rename to src/apps/dashboard/features/activity/components/LogLevelChip.tsx diff --git a/src/apps/dashboard/components/activityTable/OverviewCell.tsx b/src/apps/dashboard/features/activity/components/OverviewCell.tsx similarity index 87% rename from src/apps/dashboard/components/activityTable/OverviewCell.tsx rename to src/apps/dashboard/features/activity/components/OverviewCell.tsx index 69702de5f6..a0c453b075 100644 --- a/src/apps/dashboard/components/activityTable/OverviewCell.tsx +++ b/src/apps/dashboard/features/activity/components/OverviewCell.tsx @@ -1,12 +1,14 @@ -import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models/activity-log-entry'; import Info from '@mui/icons-material/Info'; import Box from '@mui/material/Box'; import ClickAwayListener from '@mui/material/ClickAwayListener'; import IconButton from '@mui/material/IconButton'; import Tooltip from '@mui/material/Tooltip'; -import React, { FC, useCallback, useState } from 'react'; +import React, { type FC, useCallback, useState } from 'react'; -const OverviewCell: FC = ({ Overview, ShortOverview }) => { +import type { ActivityLogEntryCell } from '../types/ActivityLogEntryCell'; + +const OverviewCell: FC = ({ row }) => { + const { ShortOverview, Overview } = row.original; const displayValue = ShortOverview ?? Overview; const [ open, setOpen ] = useState(false); diff --git a/src/apps/dashboard/features/activity/components/UserAvatarButton.tsx b/src/apps/dashboard/features/activity/components/UserAvatarButton.tsx new file mode 100644 index 0000000000..91f126e92c --- /dev/null +++ b/src/apps/dashboard/features/activity/components/UserAvatarButton.tsx @@ -0,0 +1,27 @@ +import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto'; +import IconButton from '@mui/material/IconButton/IconButton'; +import React, { type FC } from 'react'; +import { Link } from 'react-router-dom'; + +import UserAvatar from 'components/UserAvatar'; + +interface UserAvatarButtonProps { + user?: UserDto +} + +const UserAvatarButton: FC = ({ user }) => ( + user?.Id ? ( + + + + ) : undefined +); + +export default UserAvatarButton; diff --git a/src/apps/dashboard/features/activity/types/ActivityLogEntryCell.ts b/src/apps/dashboard/features/activity/types/ActivityLogEntryCell.ts new file mode 100644 index 0000000000..556f65685b --- /dev/null +++ b/src/apps/dashboard/features/activity/types/ActivityLogEntryCell.ts @@ -0,0 +1,7 @@ +import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models/activity-log-entry'; +import type { MRT_Cell, MRT_Row } from 'material-react-table'; + +export interface ActivityLogEntryCell { + cell: MRT_Cell + row: MRT_Row +} diff --git a/src/apps/dashboard/routes/activity.tsx b/src/apps/dashboard/routes/activity.tsx index 39ae92272b..a827c88ebf 100644 --- a/src/apps/dashboard/routes/activity.tsx +++ b/src/apps/dashboard/routes/activity.tsx @@ -1,34 +1,34 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import type { ActivityLogEntry } from '@jellyfin/sdk/lib/generated-client/models/activity-log-entry'; -import { LogLevel } from '@jellyfin/sdk/lib/generated-client/models/log-level'; import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto'; -import PermMedia from '@mui/icons-material/PermMedia'; import Box from '@mui/material/Box'; -import IconButton from '@mui/material/IconButton'; import ToggleButton from '@mui/material/ToggleButton'; import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; import Typography from '@mui/material/Typography'; -import { type MRT_Cell, type MRT_ColumnDef, type MRT_Row, MaterialReactTable, useMaterialReactTable } from 'material-react-table'; -import { Link, useSearchParams } from 'react-router-dom'; +import { type MRT_ColumnDef, MaterialReactTable, useMaterialReactTable } from 'material-react-table'; +import { useSearchParams } from 'react-router-dom'; +import { useLogEntires } from 'apps/dashboard/features/activity/api/useLogEntries'; +import ActionsCell from 'apps/dashboard/features/activity/components/ActionsCell'; +import LogLevelCell from 'apps/dashboard/features/activity/components/LogLevelCell'; +import OverviewCell from 'apps/dashboard/features/activity/components/OverviewCell'; +import UserAvatarButton from 'apps/dashboard/features/activity/components/UserAvatarButton'; +import type { ActivityLogEntryCell } from 'apps/dashboard/features/activity/types/ActivityLogEntryCell'; import Page from 'components/Page'; -import UserAvatar from 'components/UserAvatar'; -import { useLogEntires } from 'hooks/useLogEntries'; import { useUsers } from 'hooks/useUsers'; import { parseISO8601Date, toLocaleString } from 'scripts/datetime'; import globalize from 'lib/globalize'; import { toBoolean } from 'utils/string'; -import LogLevelChip from '../components/activityTable/LogLevelChip'; -import OverviewCell from '../components/activityTable/OverviewCell'; +type UsersRecords = Record; const DEFAULT_PAGE_SIZE = 25; const VIEW_PARAM = 'useractivity'; const enum ActivityView { - All, - User, - System + All = 'All', + User = 'User', + System = 'System' } const getActivityView = (param: string | null) => { @@ -37,6 +37,12 @@ const getActivityView = (param: string | null) => { return ActivityView.System; }; +const getUserCell = (users: UsersRecords) => function UserCell({ row }: ActivityLogEntryCell) { + return ( + + ); +}; + const Activity = () => { const [ searchParams, setSearchParams ] = useSearchParams(); @@ -50,7 +56,6 @@ const Activity = () => { const { data: usersData, isLoading: isUsersLoading } = useUsers(); - type UsersRecords = Record; const users: UsersRecords = useMemo(() => { if (!usersData) return {}; @@ -65,6 +70,8 @@ const Activity = () => { }, {}); }, [usersData]); + const UserCell = getUserCell(users); + const activityParams = useMemo(() => ({ startIndex: pagination.pageIndex * pagination.pageSize, limit: pagination.pageSize, @@ -87,11 +94,7 @@ const Activity = () => { accessorKey: 'Severity', header: globalize.translate('LabelLevel'), size: 90, - Cell: ({ cell }: { cell: MRT_Cell }) => ( - cell.getValue() ? ( - ()} /> - ) : undefined - ), + Cell: LogLevelCell, enableResizing: false, muiTableBodyCellProps: { align: 'center' @@ -102,20 +105,7 @@ const Activity = () => { accessorFn: row => row.UserId && users[row.UserId]?.Name, header: globalize.translate('LabelUser'), size: 75, - Cell: ({ row }: { row: MRT_Row }) => ( - row.original.UserId ? ( - - - - ) : undefined - ), + Cell: UserCell, enableResizing: false, visibleInShowHideMenu: activityView !== ActivityView.System, muiTableBodyCellProps: { @@ -132,9 +122,7 @@ const Activity = () => { accessorFn: row => row.ShortOverview || row.Overview, header: globalize.translate('LabelOverview'), size: 170, - Cell: ({ row }: { row: MRT_Row }) => ( - - ) + Cell: OverviewCell }, { accessorKey: 'Type', @@ -146,24 +134,13 @@ const Activity = () => { accessorFn: row => row.ItemId, header: '', size: 60, - Cell: ({ row }: { row: MRT_Row }) => ( - row.original.ItemId ? ( - - - - ) : undefined - ), + Cell: ActionsCell, enableColumnActions: false, enableColumnFilter: false, enableResizing: false, enableSorting: false } - ], [ activityView, users ]); + ], [ UserCell, activityView, users ]); const onViewChange = useCallback((_e: React.MouseEvent, newView: ActivityView | null) => { if (newView !== null) { @@ -201,6 +178,9 @@ const Activity = () => { }, // State + initialState: { + density: 'compact' + }, state: { isLoading, pagination,