rqbit/crates/librqbit/webui/src/components/FileSelectionModal.tsx

166 lines
5 KiB
TypeScript
Raw Normal View History

import { useContext, useEffect, useState } from "react";
import { Button, Modal, Form, Spinner } from "react-bootstrap";
import { AddTorrentResponse, AddTorrentOptions } from "../api-types";
import { AppContext, APIContext } from "../context";
import { ErrorComponent } from "./ErrorComponent";
import { formatBytes } from "../helper/formatBytes";
import { ErrorWithLabel } from "../rqbit-web";
export const FileSelectionModal = (props: {
onHide: () => void;
listTorrentResponse: AddTorrentResponse | null;
listTorrentError: ErrorWithLabel | null;
listTorrentLoading: boolean;
data: string | File;
}) => {
let {
onHide,
listTorrentResponse,
listTorrentError,
listTorrentLoading,
data,
} = props;
const [selectedFiles, setSelectedFiles] = useState<number[]>([]);
const [uploading, setUploading] = useState(false);
const [uploadError, setUploadError] = useState<ErrorWithLabel | null>(null);
const [unpopularTorrent, setUnpopularTorrent] = useState(false);
const [outputFolder, setOutputFolder] = useState<string>("");
const ctx = useContext(AppContext);
const API = useContext(APIContext);
useEffect(() => {
console.log(listTorrentResponse);
setSelectedFiles(
listTorrentResponse
? listTorrentResponse.details.files.map((_, id) => id)
: []
);
setOutputFolder(listTorrentResponse?.output_folder || "");
}, [listTorrentResponse]);
const clear = () => {
onHide();
setSelectedFiles([]);
setUploadError(null);
setUploading(false);
};
const handleToggleFile = (toggledId: number) => {
if (selectedFiles.includes(toggledId)) {
setSelectedFiles(selectedFiles.filter((i) => i !== toggledId));
} else {
setSelectedFiles([...selectedFiles, toggledId]);
}
};
const handleUpload = async () => {
if (!listTorrentResponse) {
return;
}
setUploading(true);
let initialPeers = listTorrentResponse.seen_peers
? listTorrentResponse.seen_peers.slice(0, 32)
: null;
let opts: AddTorrentOptions = {
overwrite: true,
only_files: selectedFiles,
initial_peers: initialPeers,
output_folder: outputFolder,
};
if (unpopularTorrent) {
opts.peer_opts = {
connect_timeout: 20,
read_write_timeout: 60,
};
}
API.uploadTorrent(data, opts)
.then(
() => {
onHide();
ctx.refreshTorrents();
},
(e) => {
setUploadError({ text: "Error starting torrent", details: e });
}
)
.finally(() => setUploading(false));
};
const getBody = () => {
if (listTorrentLoading) {
return <Spinner />;
} else if (listTorrentError) {
return <ErrorComponent error={listTorrentError}></ErrorComponent>;
} else if (listTorrentResponse) {
return (
<Form>
<fieldset className="mb-4">
<legend>Pick the files to download</legend>
{listTorrentResponse.details.files.map((file, index) => (
<Form.Group key={index} controlId={`check-${index}`}>
<Form.Check
type="checkbox"
label={`${file.name} (${formatBytes(file.length)})`}
checked={selectedFiles.includes(index)}
onChange={() => handleToggleFile(index)}
></Form.Check>
</Form.Group>
))}
</fieldset>
<fieldset>
<legend>Options</legend>
<Form.Group controlId="output-folder" className="mb-3">
<Form.Label>Output folder</Form.Label>
<Form.Control
type="text"
value={outputFolder}
onChange={(e) => setOutputFolder(e.target.value)}
/>
</Form.Group>
<Form.Group controlId="unpopular-torrent" className="mb-3">
<Form.Check
type="checkbox"
label="Increase timeouts"
checked={unpopularTorrent}
onChange={() => setUnpopularTorrent(!unpopularTorrent)}
></Form.Check>
<small id="emailHelp" className="form-text text-muted">
This might be useful for unpopular torrents with few peers. It
will slow down fast torrents though.
</small>
</Form.Group>
</fieldset>
</Form>
);
}
};
return (
<Modal show onHide={clear} size="lg">
<Modal.Header closeButton>
<Modal.Title>Add torrent</Modal.Title>
</Modal.Header>
<Modal.Body>
{getBody()}
<ErrorComponent error={uploadError} />
</Modal.Body>
<Modal.Footer>
{uploading && <Spinner />}
<Button
variant="primary"
onClick={handleUpload}
disabled={
listTorrentLoading || uploading || selectedFiles.length == 0
}
>
OK
</Button>
<Button variant="secondary" onClick={clear}>
Cancel
</Button>
</Modal.Footer>
</Modal>
);
};