mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-05 04:55:58 +01:00
perf: Improve TorrentTile rendering performance (#1951)
This commit is contained in:
@@ -1,23 +1,22 @@
|
|||||||
import { type MRT_ColumnDef, MRT_Table, useMantineReactTable } from 'mantine-react-table';
|
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
Center,
|
Center,
|
||||||
createStyles,
|
|
||||||
Flex,
|
Flex,
|
||||||
Group,
|
Group,
|
||||||
Loader,
|
Loader,
|
||||||
Popover,
|
Popover,
|
||||||
Progress,
|
Progress,
|
||||||
ScrollArea,
|
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
Title,
|
Title,
|
||||||
|
createStyles,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useElementSize } from '@mantine/hooks';
|
import { useElementSize } from '@mantine/hooks';
|
||||||
import { IconFileDownload } from '@tabler/icons-react';
|
import { IconFileDownload } from '@tabler/icons-react';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import duration from 'dayjs/plugin/duration';
|
import duration from 'dayjs/plugin/duration';
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||||
|
import { type MRT_ColumnDef, MRT_TableContainer, useMantineReactTable } from 'mantine-react-table';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { MIN_WIDTH_MOBILE } from '~/constants/constants';
|
import { MIN_WIDTH_MOBILE } from '~/constants/constants';
|
||||||
@@ -109,7 +108,6 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
|
|
||||||
const filteredTorrents = filterTorrents(widget, torrents);
|
const filteredTorrents = filterTorrents(widget, torrents);
|
||||||
|
|
||||||
|
|
||||||
const difference = new Date().getTime() - dataUpdatedAt;
|
const difference = new Date().getTime() - dataUpdatedAt;
|
||||||
const duration = dayjs.duration(difference, 'ms');
|
const duration = dayjs.duration(difference, 'ms');
|
||||||
const humanizedDuration = duration.humanize();
|
const humanizedDuration = duration.humanize();
|
||||||
@@ -117,7 +115,8 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
const ratioGlobal = getTorrentsRatio(widget, torrents, false);
|
const ratioGlobal = getTorrentsRatio(widget, torrents, false);
|
||||||
const ratioWithFilter = getTorrentsRatio(widget, torrents, true);
|
const ratioWithFilter = getTorrentsRatio(widget, torrents, true);
|
||||||
|
|
||||||
const columns = useMemo<MRT_ColumnDef<TorrentTotalDownload['torrents'][0]>[]>(() => [
|
const columns = useMemo<MRT_ColumnDef<TorrentTotalDownload['torrents'][0]>[]>(
|
||||||
|
() => [
|
||||||
{
|
{
|
||||||
id: 'dateAdded',
|
id: 'dateAdded',
|
||||||
accessorFn: (row) => new Date(row.dateAdded),
|
accessorFn: (row) => new Date(row.dateAdded),
|
||||||
@@ -138,11 +137,7 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Text
|
<Text maw={'30vw'} size="xs" lineClamp={1}>
|
||||||
maw={'30vw'}
|
|
||||||
size="xs"
|
|
||||||
lineClamp={1}
|
|
||||||
>
|
|
||||||
{String(cell.getValue())}
|
{String(cell.getValue())}
|
||||||
</Text>
|
</Text>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
@@ -188,19 +183,29 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
maxSize: 1,
|
maxSize: 1,
|
||||||
Cell: ({ cell, row }) => (
|
Cell: ({ cell, row }) => (
|
||||||
<Flex>
|
<Flex>
|
||||||
<Text className={useStyles().classes.noTextBreak}>{(Number(cell.getValue()) * 100).toFixed(1)}%</Text>
|
<Text className={useStyles().classes.noTextBreak}>
|
||||||
|
{(Number(cell.getValue()) * 100).toFixed(1)}%
|
||||||
|
</Text>
|
||||||
<Progress
|
<Progress
|
||||||
radius="lg"
|
radius="lg"
|
||||||
color={
|
color={
|
||||||
Number(cell.getValue()) === 1 ? 'green' : row.original.state === 'paused' ? 'yellow' : 'blue'
|
Number(cell.getValue()) === 1
|
||||||
|
? 'green'
|
||||||
|
: row.original.state === 'paused'
|
||||||
|
? 'yellow'
|
||||||
|
: 'blue'
|
||||||
}
|
}
|
||||||
value={Number(cell.getValue()) * 100}
|
value={Number(cell.getValue()) * 100}
|
||||||
size="lg"
|
size="lg"
|
||||||
/>,
|
/>
|
||||||
</Flex>),
|
,
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
sortDescFirst: true,
|
sortDescFirst: true,
|
||||||
},
|
},
|
||||||
], []);
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const torrentsTable = useMantineReactTable({
|
const torrentsTable = useMantineReactTable({
|
||||||
columns,
|
columns,
|
||||||
@@ -210,6 +215,9 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
enableMultiSort: true,
|
enableMultiSort: true,
|
||||||
enableColumnActions: false,
|
enableColumnActions: false,
|
||||||
enableColumnFilters: false,
|
enableColumnFilters: false,
|
||||||
|
enableRowVirtualization: true,
|
||||||
|
rowVirtualizerProps: { overscan: 20 },
|
||||||
|
mantineTableContainerProps: { sx: { scrollbarWidth: 'none' } },
|
||||||
enableSorting: true,
|
enableSorting: true,
|
||||||
initialState: {
|
initialState: {
|
||||||
showColumnFilters: false,
|
showColumnFilters: false,
|
||||||
@@ -238,7 +246,6 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
@@ -288,10 +295,8 @@ function TorrentTile({ widget }: TorrentTileProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" sx={{ height: '100%' }} ref={ref}>
|
<Flex direction="column" sx={{ height: '100%', isolation: 'isolate' }} ref={ref}>
|
||||||
<ScrollArea style={{ flexGrow: 1 }}>
|
<MRT_TableContainer table={torrentsTable} />
|
||||||
<MRT_Table table={torrentsTable} />
|
|
||||||
</ScrollArea>
|
|
||||||
<Group spacing="sm">
|
<Group spacing="sm">
|
||||||
{data.apps.some((x) => !x.success) && (
|
{data.apps.some((x) => !x.success) && (
|
||||||
<Badge variant="dot" color="red">
|
<Badge variant="dot" color="red">
|
||||||
@@ -320,7 +325,7 @@ export const filterTorrents = (widget: ITorrent, torrents: TorrentTotalDownload[
|
|||||||
(torrent) =>
|
(torrent) =>
|
||||||
!torrent.isCompleted ||
|
!torrent.isCompleted ||
|
||||||
(widget.properties.displayActiveTorrents &&
|
(widget.properties.displayActiveTorrents &&
|
||||||
torrent.uploadSpeed > widget.properties.speedLimitOfActiveTorrents * 1024),
|
torrent.uploadSpeed > widget.properties.speedLimitOfActiveTorrents * 1024)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +333,7 @@ export const filterTorrents = (widget: ITorrent, torrents: TorrentTotalDownload[
|
|||||||
result = filterTorrentsByLabels(
|
result = filterTorrentsByLabels(
|
||||||
result,
|
result,
|
||||||
widget.properties.labelFilter,
|
widget.properties.labelFilter,
|
||||||
widget.properties.labelFilterIsWhitelist,
|
widget.properties.labelFilterIsWhitelist
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +353,7 @@ const filterStaleTorrent = (widget: ITorrent, torrents: TorrentTotalDownload['to
|
|||||||
const filterTorrentsByLabels = (
|
const filterTorrentsByLabels = (
|
||||||
torrents: TorrentTotalDownload['torrents'],
|
torrents: TorrentTotalDownload['torrents'],
|
||||||
labels: string[],
|
labels: string[],
|
||||||
isWhitelist: boolean,
|
isWhitelist: boolean
|
||||||
) => {
|
) => {
|
||||||
if (isWhitelist) {
|
if (isWhitelist) {
|
||||||
return torrents.filter((torrent) => torrent.label && labels.includes(torrent.label));
|
return torrents.filter((torrent) => torrent.label && labels.includes(torrent.label));
|
||||||
@@ -360,7 +365,7 @@ const filterTorrentsByLabels = (
|
|||||||
export const getTorrentsRatio = (
|
export const getTorrentsRatio = (
|
||||||
widget: ITorrent,
|
widget: ITorrent,
|
||||||
torrents: TorrentTotalDownload['torrents'],
|
torrents: TorrentTotalDownload['torrents'],
|
||||||
applyAllFilter: boolean,
|
applyAllFilter: boolean
|
||||||
) => {
|
) => {
|
||||||
if (applyAllFilter) {
|
if (applyAllFilter) {
|
||||||
torrents = filterTorrents(widget, torrents);
|
torrents = filterTorrents(widget, torrents);
|
||||||
@@ -368,18 +373,14 @@ export const getTorrentsRatio = (
|
|||||||
torrents = filterTorrentsByLabels(
|
torrents = filterTorrentsByLabels(
|
||||||
torrents,
|
torrents,
|
||||||
widget.properties.labelFilter,
|
widget.properties.labelFilter,
|
||||||
widget.properties.labelFilterIsWhitelist,
|
widget.properties.labelFilterIsWhitelist
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let totalDownloadedSum = torrents.reduce(
|
let totalDownloadedSum = torrents.reduce((sum, torrent) => sum + torrent.totalDownloaded, 0);
|
||||||
(sum, torrent) => sum + torrent.totalDownloaded,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
|
|
||||||
return totalDownloadedSum > 0
|
return totalDownloadedSum > 0
|
||||||
? torrents.reduce((sum, torrent) => sum + torrent.totalUploaded, 0) /
|
? torrents.reduce((sum, torrent) => sum + torrent.totalUploaded, 0) / totalDownloadedSum
|
||||||
totalDownloadedSum
|
|
||||||
: -1;
|
: -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user