<commit_before>import { useState, useCallback, useEffect } from 'react';

import { Transfer, TransferProgresses, TransfersStats, TransferState, TransferStats } from '../../interfaces/transfer';
import { isTransferProgress } from '../../utils/transfer';

const PROGRESS_UPDATE_INTERVAL = 500;
const SPEED_SNAPSHOTS = 10; // How many snapshots should the speed be average of

function useStatsHistory(transfers: Transfer[], getTransferProgresses: () => TransferProgresses) {
    const [statsHistory, setStatsHistory] = useState<TransfersStats[]>([]);

    const getTransfer = useCallback((id: string) => transfers.find((transfer) => transfer.id === id), [transfers]);

    const updateStats = () => {
        const timestamp = new Date();
        const transferProgresses = getTransferProgresses();

        setStatsHistory((prev) => {
            const lastStats = (id: string) => prev[0]?.stats[id] || {};
            const stats = Object.entries(transferProgresses).reduce(
                (stats, [id, progress]) => ({
                    ...stats,
                    [id]: {
                        // get speed snapshot based on bytes downloaded since last update
                        speed: lastStats(id).active
                            ? (transferProgresses[id] - lastStats(id).progress) * (1000 / PROGRESS_UPDATE_INTERVAL)
                            : 0,
                        active: getTransfer(id)?.state === TransferState.Progress,
                        progress,
                    },
                }),
                {} as { [id: string]: TransferStats }
            );

            return [{ stats, timestamp }, ...prev.slice(0, SPEED_SNAPSHOTS - 1)];
        });
    };

    useEffect(() => {
        updateStats();

        const transfersInProgress = transfers.filter(isTransferProgress);

        if (!transfersInProgress.length) {
            return;
        }

        const int = setInterval(updateStats, PROGRESS_UPDATE_INTERVAL);

        return () => {
            clearInterval(int);
        };
    }, [transfers]);

    return statsHistory;
}

export default useStatsHistory;
<commit_msg>Update progresses after upload is paused<commit_after>import { useState, useCallback, useEffect } from 'react';

import { Transfer, TransferProgresses, TransfersStats, TransferState, TransferStats } from '../../interfaces/transfer';
import { isTransferProgress } from '../../utils/transfer';

const PROGRESS_UPDATE_INTERVAL = 500;
const SPEED_SNAPSHOTS = 10; // How many snapshots should the speed be average of

function useStatsHistory(transfers: Transfer[], getTransferProgresses: () => TransferProgresses) {
    const [statsHistory, setStatsHistory] = useState<TransfersStats[]>([]);

    const getTransfer = useCallback((id: string) => transfers.find((transfer) => transfer.id === id), [transfers]);

    const updateStats = () => {
        const timestamp = new Date();
        const transferProgresses = getTransferProgresses();

        setStatsHistory((prev) => {
            const lastStats = (id: string) => prev[0]?.stats[id] || {};
            const stats = Object.entries(transferProgresses).reduce(
                (stats, [id, progress]) => ({
                    ...stats,
                    [id]: {
                        // get speed snapshot based on bytes downloaded since last update
                        speed: lastStats(id).active
                            ? (transferProgresses[id] - lastStats(id).progress) * (1000 / PROGRESS_UPDATE_INTERVAL)
                            : 0,
                        active: getTransfer(id)?.state === TransferState.Progress,
                        progress,
                    },
                }),
                {} as { [id: string]: TransferStats }
            );

            return [{ stats, timestamp }, ...prev.slice(0, SPEED_SNAPSHOTS - 1)];
        });
    };

    useEffect(() => {
        updateStats();

        const transfersInProgress = transfers.filter(isTransferProgress);

        if (!transfersInProgress.length) {
            return;
        }

        const int = setInterval(updateStats, PROGRESS_UPDATE_INTERVAL);

        return () => {
            // When transfer is paused, progress is updated a bit later.
            // Therefore we need to update stats even few ms after nothing
            // is in progress.
            setTimeout(updateStats, PROGRESS_UPDATE_INTERVAL);
            clearInterval(int);
        };
    }, [transfers]);

    return statsHistory;
}

export default useStatsHistory;

{'fraction_non_alphanumeric': 0.11989401633914772, 'fraction_numerical': 0.005740781629498786, 'mean_word_length': 2.087934560327198, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4329821', 'n_tokens_mistral': 1165, 'n_tokens_neox': 1108, 'n_words': 279}