// core/torrent-handler/components/TorrentDashboard.js
import React, { useState, useEffect } from 'react';
export const TorrentDashboard = ({ core }) => {
const [torrents, setTorrents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const loadTorrents = async () => {
setLoading(true);
try {
const torrentList = await core.getTorrents();
setTorrents(torrentList);
setError(null);
} catch (err) {
setError('Failed to load torrents: ' + err.message);
} finally {
setLoading(false);
}
};
// Load torrents on component mount
useEffect(() => {
loadTorrents();
// Set up refresh interval
const interval = setInterval(loadTorrents, 3000);
// Clean up interval on unmount
return () => clearInterval(interval);
}, []);
const handleStart = async (torrentId) => {
try {
await core.startTorrent(torrentId);
loadTorrents();
} catch (err) {
setError('Failed to start torrent: ' + err.message);
}
};
const handleStop = async (torrentId) => {
try {
await core.stopTorrent(torrentId);
loadTorrents();
} catch (err) {
setError('Failed to stop torrent: ' + err.message);
}
};
const handleRemove = async (torrentId, deleteData) => {
if (confirm(`Are you sure you want to remove this torrent${deleteData ? ' and its data' : ''}?`)) {
try {
await core.removeTorrent(torrentId, deleteData);
loadTorrents();
} catch (err) {
setError('Failed to remove torrent: ' + err.message);
}
}
};
// Helper function to format size
const formatSize = (bytes) => {
if (bytes === 0) return '0 B';
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
};
// Helper function to format status
const getStatusText = (status) => {
const statusMap = {
0: 'Stopped',
1: 'Queued to check',
2: 'Checking',
3: 'Queued to download',
4: 'Downloading',
5: 'Queued to seed',
6: 'Seeding'
};
return statusMap[status] || 'Unknown';
};
return (
Torrent Dashboard
{error && (
);
};
// core/torrent-handler/components/index.js
// Export all components for easier imports
export { TorrentDashboard } from './TorrentDashboard';
export { AddTorrentForm } from './AddTorrentForm';
export { TorrentSettings } from './TorrentSettings';
error-message">
{error}
)}
{loading && torrents.length === 0 ? (
Loading torrents...
) : torrents.length === 0 ? (
) : (
)}
);
};
// core/torrent-handler/components/AddTorrentForm.js
import React, { useState } from 'react';
export const AddTorrentForm = ({ core, navigate }) => {
const [torrentFile, setTorrentFile] = useState(null);
const [seedRatio, setSeedRatio] = useState(core.config.default_seed_ratio);
const [seedTime, setSeedTime] = useState(core.config.default_seed_time);
const [autoStart, setAutoStart] = useState(core.config.auto_start_torrents);
const [downloadDir, setDownloadDir] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const handleFileChange = (e) => {
const file = e.target.files[0];
if (file && (file.name.endsWith('.torrent') || file.type === 'application/x-bittorrent')) {
setTorrentFile(file);
setError(null);
} else {
setTorrentFile(null);
setError('Please select a valid .torrent file');
}
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!torrentFile) {
setError('Please select a torrent file');
return;
}
setLoading(true);
setError(null);
try {
await core.addTorrent(torrentFile, {
seedRatio: parseFloat(seedRatio),
seedTime: parseInt(seedTime, 10),
autoStart: autoStart,
downloadDirectory: downloadDir || undefined
});
// Redirect to dashboard
navigate('/torrents');
} catch (err) {
setError('Failed to add torrent: ' + err.message);
setLoading(false);
}
};
return (
Add New Torrent
{error && (
{error}
)}
);
};
// core/torrent-handler/components/TorrentSettings.js
import React, { useState } from 'react';
export const TorrentSettings = ({ core, navigate }) => {
const [settings, setSettings] = useState({
default_seed_ratio: core.config.default_seed_ratio,
default_seed_time: core.config.default_seed_time,
auto_start_torrents: core.config.auto_start_torrents,
transmission_url: core.config.transmission_url,
transmission_username: core.config.transmission_username,
transmission_password: core.config.transmission_password
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setSettings({
...settings,
[name]: type === 'checkbox' ? checked : value
});
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
setSuccess(false);
try {
// Update core configuration
core.config = { ...core.config, ...settings };
// Save configuration to framework persistence
await core.framework.saveConfiguration(core.id, core.config);
setSuccess(true);
} catch (err) {
setError('Failed to save settings: ' + err.message);
} finally {
setLoading(false);
}
};
const handleTestConnection = async () => {
setLoading(true);
setError(null);
setSuccess(false);
try {
// Temporarily update connection settings
const originalConfig = { ...core.config };
core.config = {
...core.config,
transmission_url: settings.transmission_url,
transmission_username: settings.transmission_username,
transmission_password: settings.transmission_password
};
// Test connection
await core.connectToTransmission();
setSuccess('Connection successful!');
} catch (err) {
setError('Connection test failed: ' + err.message);
} finally {
setLoading(false);
}
};
return (
Torrent Settings
{error && (
{error}
)}
{success && (
{typeof success === 'string' ? success : 'Settings saved successfully!'}
)}