The UI looks good now

This commit is contained in:
Igor Katson 2023-11-22 20:52:50 +00:00
parent 9704597804
commit 27e8c12cfe
No known key found for this signature in database
GPG key ID: B4EC22B66D61A3F5

View file

@ -93,41 +93,56 @@ interface TorrentStats {
}; };
time_remaining: { time_remaining: {
human_readable: string; human_readable: string;
duration: {
secs: number,
}
} | null; } | null;
} }
const TorrentRow: React.FC<{ const TorrentRow: React.FC<{
detailsResponse: TorrentDetails, statsResponse: TorrentStats id: number, detailsResponse: TorrentDetails, statsResponse: TorrentStats
}> = ({ detailsResponse, statsResponse }) => { }> = ({ id, detailsResponse, statsResponse }) => {
const totalBytes = statsResponse.snapshot.total_bytes; const totalBytes = statsResponse.snapshot.total_bytes;
const downloadedBytes = statsResponse.snapshot.have_bytes; const downloadedBytes = statsResponse.snapshot.have_bytes;
const finished = totalBytes == downloadedBytes; const finished = totalBytes == downloadedBytes;
const downloadPercentage = (downloadedBytes / totalBytes) * 100; const downloadPercentage = (downloadedBytes / totalBytes) * 100;
let classes = [
];
if (id % 2 == 0) {
classes.push('bg-light');
}
return ( return (
<tr className="torrent-row"> <Row className={classes.join(' ')}>
<Column label="Name">{getLargestFileName(detailsResponse)}</Column> <Column size={4} label="Name">
<Column label="Size">{`${formatBytes(totalBytes)}`}</Column> <div className='text-truncate'>
<Column label="Progress"> {getLargestFileName(detailsResponse)}
<ProgressBar now={downloadPercentage} label={`${downloadPercentage.toFixed(2)}%`} animated={!finished} style={{ 'minWidth': '200px' }} /> </div>
</Column> </Column>
<Column label="Download Speed">{statsResponse.download_speed.human_readable}</Column> <Column label="Size">{`${formatBytes(totalBytes)}`}</Column>
<Column size={2} label="Progress">
<ProgressBar now={downloadPercentage} label={`${downloadPercentage.toFixed(2)}%`} animated={!finished} />
</Column>
<Column size={2} label="Down Speed">{statsResponse.download_speed.human_readable}</Column>
<Column label="ETA">{getCompletionETA(statsResponse)}</Column> <Column label="ETA">{getCompletionETA(statsResponse)}</Column>
<Column label="Peers">{`${statsResponse.snapshot.peer_stats.live} / ${statsResponse.snapshot.peer_stats.seen}`}</Column> <Column size={2} label="Peers">{`${statsResponse.snapshot.peer_stats.live} / ${statsResponse.snapshot.peer_stats.seen}`}</Column>
</tr > </Row>
); );
} }
const Column: React.FC<{ const Column: React.FC<{
label: string, label: string,
size?: number,
children?: any children?: any
}> = ({ children }) => ( }> = ({ size, label, children }) => (
<td className='me-3 p-3'> <Col md={size || 1} className='py-3'>
<div className='fw-bold'>{label}</div>
{children} {children}
</td> </Col>
); );
const Torrent = ({ torrent }) => { const Torrent = ({ id, torrent }) => {
const defaultDetails: TorrentDetails = { const defaultDetails: TorrentDetails = {
info_hash: '', info_hash: '',
files: [] files: []
@ -202,7 +217,7 @@ const Torrent = ({ torrent }) => {
return clear; return clear;
}, []); }, []);
return <TorrentRow detailsResponse={detailsResponse} statsResponse={statsResponse} /> return <TorrentRow id={id} detailsResponse={detailsResponse} statsResponse={statsResponse} />
} }
const TorrentsList = (props: { torrents: Array<TorrentId>, loading: boolean }) => { const TorrentsList = (props: { torrents: Array<TorrentId>, loading: boolean }) => {
@ -222,24 +237,11 @@ const TorrentsList = (props: { torrents: Array<TorrentId>, loading: boolean }) =
) )
} }
return ( return (
<Table className='text-center table-striped table-hover table-borderless'> <>
<thead> {props.torrents.map((t: TorrentId) =>
<tr> <Torrent id={t.id} key={t.id} torrent={t} />
<th>Name</th> )}
<th>Size</th> </>
<th>Progress</th>
<th>Download Speed</th>
<th>ETA</th>
<th>Peers</th>
</tr>
</thead>
<tbody>
{props.torrents.map((t: TorrentId) =>
<Torrent key={t.id} torrent={t} />
)}
</tbody>
</Table>
) )
}; };
@ -334,14 +336,14 @@ const Root = () => {
} }
return <AppContext.Provider value={context}> return <AppContext.Provider value={context}>
<Container className='text-center'> <div className='text-center'>
<h1 className="mt-3 mb-4">rqbit web 0.0.1-alpha</h1> <h1 className="mt-3 mb-4">rqbit web 0.0.1-alpha</h1>
<RootContent <RootContent
closeableError={closeableError} closeableError={closeableError}
otherError={otherError} otherError={otherError}
torrents={torrents} torrents={torrents}
torrentsLoading={torrentsLoading} /> torrentsLoading={torrentsLoading} />
</Container> </div>
</AppContext.Provider > </AppContext.Provider >
} }
@ -608,13 +610,29 @@ function getLargestFileName(torrentDetails: TorrentDetails): string {
// Function to get the completion ETA of a torrent // Function to get the completion ETA of a torrent
function getCompletionETA(stats: TorrentStats): string { function getCompletionETA(stats: TorrentStats): string {
if (stats.time_remaining) { if (stats.time_remaining && stats.time_remaining.duration) {
return stats.time_remaining.human_readable; return formatSecondsToTime(stats.time_remaining.duration.secs);
} else { } else {
return 'N/A'; return 'N/A';
} }
} }
function formatSecondsToTime(seconds: number) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
const formatUnit = (value, unit) => (value > 0 ? `${value}${unit}` : '');
if (hours > 0) {
return `${formatUnit(hours, 'h')} ${formatUnit(minutes, 'm')}`.trim();
} else if (minutes > 0) {
return `${formatUnit(minutes, 'm')} ${formatUnit(remainingSeconds, 's')}`.trim();
} else {
return `${formatUnit(remainingSeconds, 's')}`.trim();
}
}
function customSetInterval(asyncCallback: any, interval: number) { function customSetInterval(asyncCallback: any, interval: number) {
let timeoutId: number; let timeoutId: number;
let currentInterval: number = interval; let currentInterval: number = interval;