Added logging, changed some directory structure

This commit is contained in:
2018-01-13 21:33:40 -05:00
parent f079a5f067
commit 8e72ffb917
73656 changed files with 35284 additions and 53718 deletions

View File

@@ -0,0 +1,286 @@
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTooltip from 'react-tooltip'
import BackendIcon from 'material-ui-icons/InfoOutline';
import {connect} from 'react-redux';
import * as actionTypes from '../store/actions';
import Select from 'material-ui/Select/Select';
var title = document.title; //Set the number of active torrents in the title
let torrents= [];
let peerList = [];
let fileList = [];
let RSSList = [];
let RSSTorrentList = [];
var torrentListRequest = {
messageType: "torrentListRequest"
}
//websocket is started in kickwebsocket.js and is picked up here so "ws" is already defined 22
ws.onmessage = function (evt) { //When we recieve a message from the websocket
var serverMessage = JSON.parse(evt.data)
//console.log("message", serverMessage.MessageType)
switch (serverMessage.MessageType) {
case "torrentList":
//console.log("Recieved Client Update...", serverMessage)
//var serverMessage = JSON.parse(evt.data);
torrents = []; //clearing out the torrent array to make room for new (so that it does keep adding)
for(var i = 0; i < serverMessage.total; i++){
torrents.push({
TorrentHashString: serverMessage.data[i].TorrentHashString,
TorrentName: serverMessage.data[i].TorrentName,
DownloadedSize: serverMessage.data[i].DownloadedSize,
Size: serverMessage.data[i].Size,
DownloadSpeed: serverMessage.data[i].DownloadSpeed,
UploadSpeed: serverMessage.data[i].UploadSpeed,
PercentDone: serverMessage.data[i].PercentDone,
StoragePath: serverMessage.data[i].StoragePath,
DateAdded: serverMessage.data[i].DateAdded,
SourceType: serverMessage.data[i].SourceType,
Status: serverMessage.data[i].Status,
BytesCompleted: serverMessage.data[i].BytesCompleted,
ActivePeers: serverMessage.data[i].ActivePeers,
ETA: serverMessage.data[i].ETA,
TotalUploadedSize: serverMessage.data[i].TotalUploadedSize,
Ratio: serverMessage.data[i].UploadRatio,
FileNumber: serverMessage.data[i].NumberofFiles,
PieceNumber: serverMessage.data[i].NumberofPieces,
})
}
var newTitle = '(' + serverMessage.total + ')' + title; //updating the title
document.title = newTitle;
break;
case "torrentPeerList":
peerList = []; //clearing out the peerlist array to make room for new (so that it does keep adding)
for(var i = 0; i < serverMessage.TotalPeers; i++){
peerList.push({
PeerID: serverMessage.PeerList[i].Id.toString(),
IP: serverMessage.PeerList[i].IP,
Port: serverMessage.PeerList[i].Port,
Source: serverMessage.PeerList[i].Source,
SupportsEncryption: serverMessage.PeerList[i].SupportsEncryption.toString(),
})
}
break
case "torrentFileList":
fileList = [];
for (var i = 0; i < serverMessage.TotalFiles; i++){
fileList.push({
FileName: serverMessage.FileList[i].FileName,
FilePath: serverMessage.FileList[i].FilePath,
FileSize: serverMessage.FileList[i].FileSize,
FilePercent: serverMessage.FileList[i].FilePercent,
FilePriority: serverMessage.FileList[i].FilePriority,
})
}
console.log("filelist", fileList)
break
case "speedTab":
console.log("Speedtab data requested")
break;
case "loggerData":
console.log("Logger data requested")
break;
case "rssListRequest":
console.log("RSSListRequest recieved", evt.data)
RSSList = [];
for (var i = 0; i < serverMessage.TotalRSSFeeds; i++){
RSSList.push({
RSSURL: serverMessage.RSSFeeds[i].RSSFeedURL,
RSSName: serverMessage.RSSFeeds[i].RSSName,
})
}
console.log("RSSURLS", RSSList)
console.log("FIRSTURL", RSSList[1])
console.log("FULLURL", RSSList[1].RSSURL)
break;
case "rssTorrentList":
//console.log("RSSTorrentList recieved", evt.data)
RSSTorrentList = [];
for (var i = 0; i < serverMessage.TotalTorrents; i++){
RSSTorrentList.push({
TorrentName: serverMessage.Torrents[i].Title,
TorrentLink: serverMessage.Torrents[i].Link,
PublishDate: serverMessage.Torrents[i].PubDate,
})
}
}
}
ws.onclose = function() {
console.log('Closing connection')
};
var divStyle = {
display: 'inline-block',
paddingTop: '10px',
paddingLeft: '10px',
}
var buttonStyle ={
fontSize: '60px',
}
class BackendSocket extends React.Component {
selectionHandler = (selectionHashes, selectedTab) => {
switch (selectedTab) {
case 0:
console.log("general tab information requested")
break;
case 1:
let peerListHashes = {
MessageType: "torrentPeerListRequest",
Payload: selectionHashes,
}
console.log("Peers tab information requested", peerListHashes)
ws.send(JSON.stringify(peerListHashes))
break;
case 2:
let fileListHashes = {
MessageType: "torrentFileListRequest",
Payload: selectionHashes,
}
console.log("Files tab information requested", fileListHashes)
ws.send(JSON.stringify(fileListHashes))
break;
case 3:
console.log("Speed tab information requested")
break;
case 4:
console.log("Logger tab information requested")
break;
default:
console.log("default tab")
break;
}
}
testSelectionLength = (selection) => {
if (nextProps.selectionHashes.length > 1){
return true;
}
return false;
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
2000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() { // this tick is the main tick that updates ALL of the components that update on tick... which is a lot
if (this.props.RSSList != RSSList & this.props.RSSModalOpen == true) {
this.props.newRSSFeedStore(RSSList) //pushing the new RSSList to Redux
}
if (this.props.RSSTorrentList != RSSTorrentList & this.props.RSSModalOpen == true){
this.props.RSSTorrentList(RSSTorrentList) //pushing the new RSSTorrentList to Redux
}
ws.send(JSON.stringify(torrentListRequest))//talking to the server to get the torrent list
//console.log("Torrentlist", torrents)
this.props.setButtonState(this.props.selection) //forcing an update to the buttons
this.props.newTorrentList(torrents) //sending the list of torrents to torrentlist.js
if (this.props.selectionHashes.length === 1){
switch(this.props.selectedTab){
case 1:
let peerListHashes = {
MessageType: "torrentPeerListRequest",
Payload: this.props.selectionHashes,
}
ws.send(JSON.stringify(peerListHashes))
this.props.newPeerList(peerList)
break;
case 2:
let fileListHashes = {
MessageType: "torrentFileListRequest",
Payload: this.props.selectionHashes,
}
ws.send(JSON.stringify(fileListHashes))
this.props.newFileList(fileList)
break;
}
}
}
componentWillReceiveProps (nextProps) {
console.log("Lenght", nextProps.selectionHashes.length, "value", nextProps.selectionHashes)
if (nextProps.selectionHashes.length === 1){ //if we have a selection pass it on for the tabs to verify
this.selectionHandler(nextProps.selectionHashes, nextProps.selectedTab)
}
}
render() {
return (
<div style={divStyle}>
<BackendIcon styles={buttonStyle} color="primary" data-tip="BackendStatus: Green=Good" aria-label="Settings" />
</div>
);
}
}
const mapStateToProps = state => {
return {
selectionHashes: state.selectionHashes,
selectedTab: state.selectedTab,
selection: state.selection,
RSSModalOpen: state.RSSModalOpen,
RSSTorrentList: state.RSSTorrentList,
};
}
const mapDispatchToProps = dispatch => {
return {
newTorrentList: (torrentList) => dispatch({type: actionTypes.TORRENT_LIST, torrentList }),
newPeerList: (peerList) => dispatch({type: actionTypes.PEER_LIST, peerList}),
newFileList: (fileList) => dispatch({type: actionTypes.FILE_LIST, fileList}),
setButtonState: (buttonState) => dispatch({type: actionTypes.SET_BUTTON_STATE, buttonState}),
newRSSFeedStore: (RSSList) => dispatch({type: actionTypes.NEW_RSS_FEED_STORE, RSSList}),
RSSTorrentList: (RSSTorrentList) => dispatch({type: actionTypes.RSS_TORRENT_LIST, RSSTorrentList}),
//changeSelection: (selection) => dispatch({type: actionTypes.CHANGE_SELECTION, selection}),//forcing an update to the buttons
}
}
export default connect(mapStateToProps, mapDispatchToProps)(BackendSocket);

View File

@@ -0,0 +1,156 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import { ProgressBarCell } from '../../CustomCells/progressBarCell';
import {
SortingState, LocalSorting, VirtualTableLayout, SelectionState,
} from '@devexpress/dx-react-grid';
import {
Grid, TableHeaderRow, PagingPanel, VirtualTableView, TableColumnResizing,
DragDropContext, TableColumnReordering, TableSelection,
} from '@devexpress/dx-react-grid-material-ui';
import {connect} from 'react-redux';
import * as actionTypes from '../../store/actions';
class FileTab extends React.Component {
constructor(props) {
super(props);
this.state = { //rows are stored in redux they are sent over from the server
columns: [
{ name: 'FileName', title: 'File Name'},
{ name: 'FilePath', title: 'File Path' },
{ name: 'FileSize', title: 'File Size'},
{ name: 'FilePercent', title: 'File Percent'},
{ name: 'FilePriority', title: 'File Priority'},
],
sorting: [],
columnOrder: ['FileName', 'FilePath', 'FileSize', 'FilePercent', 'FilePriority'],
columnWidths: {FileName: 450, FilePath: 650, FileSize: 100, FilePercent: 100, FilePriority: 75},
fileSelection: [],
selected: [],
};
this.changeColumnOrder = columnOrder => this.setState({columnOrder});
this.changeColumnWidths = columnWidths => this.setState({columnWidths});
this.changeSorting = sorting => this.setState({sorting});
}
changeSelection = (selection) => {
console.log("Filelist is changing selection now", selection)
this.setState({selected: selection})
if (selection.length > 0) { //if selection is empty buttons will be default and selectionHashes will be blanked out and pushed to redux
console.log("Getting the selected Rows")
const selectedRows = [] //array of all the selected Rows
selection.forEach(element => {
selectedRows.push(this.props.fileList[element]) //pushing the selected rows out of torrentlist
});
this.setState({fileSelection: selectedRows})
}
}
sendPriorityRequest = (priority, sendfileNames) => {
this.state.fileSelection.forEach(element => {
console.log("element", element)
sendFileNames.push(element.FilePath)
})
let setFilePriority = {
MessageType: "setFilePriority",
Payload: sendFileNames,
}
console.log(JSON.stringify(setFilePriority))
ws.send(JSON.stringify(setFilePriority))
}
setHighPriority = () => {
let priorty = "High"
let selectionHash = this.props.selectionHashes[0] //getting the first element (should be the only one)
let sendFileNames = [selectionHash, "High"]// adding the selection hash as the first element will be stripped out by the server, second element is the prioty request
}
setNormalPriority = () => {
let priorty = "Normal"
let selectionHash = this.props.selectionHashes[0] //getting the first element (should be the only one)
let sendFileNames = [selectionHash, "Normal"]// adding the selection hash as the first element will be stripped out by the server, second element is the prioty request
}
setCancelPriority = () => {
let priorty = "Cancel"
let selectionHash = this.props.selectionHashes[0] //getting the first element (should be the only one)
let sendFileNames = [selectionHash, "Cancel"]// adding the selection hash as the first element will be stripped out by the server, second element is the prioty request
}
render() {
return (
//Buttons here
<div>
Set File Priority:
<Button raised color="primary" onClick={this.setHighPriority}>
High
</Button>
<Button raised color="primary" onClick={this.setNormalPriority}>
Normal
</Button>
<Button raised color="accent" onClick={this.setCancelPriority}>
Do Not Download
</Button>
<Grid rows={this.props.fileList} columns={this.state.columns}>
<SortingState sorting={this.state.sorting} onSortingChange={this.changeSorting} />
<LocalSorting />
<DragDropContext />
<SelectionState onSelectionChange={this.changeSelection} selection={this.state.selection}/>
<VirtualTableView height={300} tableCellTemplate={({ row, column, style }) => {
if (column.name === 'FilePercent') {
return (
<ProgressBarCell value={row.FilePercent * 100} style={style} />
);
}
return undefined;
}}/>/>
<TableColumnResizing columnWidths={this.state.columnWidths} onColumnWidthsChange={this.changeColumnWidths}/>
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
<TableSelection selectByRowClick highlightSelected />
<TableHeaderRow allowSorting allowResizing allowDragging />
</Grid>
</div>
);
}
}
const mapStateToProps = state => {
return {
selectionHashes: state.selectionHashes,
fileList: state.fileList,
//fileSelectionNames: state.fileSelectionNames,
};
}
const mapDispatchToProps = dispatch => {
return {
//changeFileSelection: (fileSelection) => dispatch({type: actionTypes.CHANGE_FILE_SELECTION, fileSelection}),
sendSelectionHashes: (selectionHashes) => dispatch({type: actionTypes.SELECTION_HASHES, selectionHashes}),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(FileTab)

View File

@@ -0,0 +1,106 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { withStyles } from 'material-ui/styles';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';
import {connect} from 'react-redux';
import * as actionTypes from '../../store/actions';
const styles = theme => ({
root: {
flexGrow: 1,
marginTop: 0,
},
paper: {
padding: 16,
textAlign: 'left',
color: theme.palette.text.primary,
},
floatRight: {
float: 'right',
}
});
class GeneralTab extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedTorrent: []
}
}
componentWillReceiveProps = () => {
//console.log("recieving props in generaltab", "TYPE", this.props.selectionHashes[Object.keys(this.props.selectionHashes)[0]])
if (this.props.selectionHashes.length === 1) { //if one torrent is selected
let selectionHashTemp = this.props.selectionHashes[Object.keys(this.props.selectionHashes)[0]]// extract out the hash of the single selection
let selectedTorrentTemp = []
this.props.torrentList.forEach(function(singleTorrent){
if (singleTorrent.TorrentHashString === selectionHashTemp){
selectedTorrentTemp = singleTorrent
}
})
//selectedTorrentTemp = this.props.torrentList.filter(torrent => torrent.TorrentHashString === this.props.selectionHashes)
//console.log("SelectedTorrentTemp", selectedTorrentTemp)
this.setState({ selectedTorrent: selectedTorrentTemp });
} else {
this.setState({ selectedTorrent: [] })
}
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Grid container spacing={8}>
<Grid item xs={12} sm={4}>
<Paper className={classes.paper}>Torrent Name: <span className={classes.floatRight}>{this.state.selectedTorrent["TorrentName"]} </span></Paper>
<Paper className={classes.paper}>Torrent Size: <span className={classes.floatRight}>{this.state.selectedTorrent["Size"]} </span> </Paper>
<Paper className={classes.paper}>Storage Path: <span className={classes.floatRight}>{this.state.selectedTorrent["StoragePath"]} </span> </Paper>
<Paper className={classes.paper}>Date Added: <span className={classes.floatRight}> {this.state.selectedTorrent["DateAdded"]} </span> </Paper>
<Paper className={classes.paper}>Source Type: <span className={classes.floatRight}> {this.state.selectedTorrent["SourceType"]} </span> </Paper>
<Paper className={classes.paper}>Label: <span className={classes.floatRight}> None </span> </Paper>
<Paper className={classes.paper}>Torrent Hash: <span className={classes.floatRight}> {this.state.selectedTorrent["TorrentHashString"]} </span> </Paper>
</Grid>
<Grid item xs={12} sm={4}>
<Paper className={classes.paper}>Status: <span className={classes.floatRight}>{this.state.selectedTorrent["Status"]} </span> </Paper>
<Paper className={classes.paper}>Percent Done: <span className={classes.floatRight}>{this.state.selectedTorrent["PercentDone"]} </span> </Paper>
<Paper className={classes.paper}>Torrent DL Amount: <span className={classes.floatRight}>{this.state.selectedTorrent["DownloadedSize"]} </span> </Paper>
<Paper className={classes.paper}>Total Upload Amount: <span className={classes.floatRight}>{this.state.selectedTorrent["TotalUploadedSize"]} </span> </Paper>
<Paper className={classes.paper}>Seeding Ratio: <span className={classes.floatRight}>{this.state.selectedTorrent["Ratio"]} </span> </Paper>
<Paper className={classes.paper}>ETA: <span className={classes.floatRight}>{this.state.selectedTorrent["ETA"]} </span> </Paper>
</Grid>
<Grid item xs={12} sm={4}>
<Paper className={classes.paper}>Number of Files: <span className={classes.floatRight}>{this.state.selectedTorrent["FileNumber"]} </span> </Paper>
<Paper className={classes.paper}>Number of Pieces: <span className={classes.floatRight}>{this.state.selectedTorrent["PieceNumber"]} </span> </Paper>
</Grid>
</Grid>
</div>
);
}
}
const mapStateToProps = state => {
return {
selectionHashes: state.selectionHashes,
torrentList: state.torrentList,
};
}
export default withStyles(styles)(connect(mapStateToProps)(GeneralTab))

View File

@@ -0,0 +1,69 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
import {
SortingState, LocalSorting, VirtualTableLayout, SelectionState,
} from '@devexpress/dx-react-grid';
import {
Grid, TableView, TableHeaderRow, PagingPanel, VirtualTableView, TableColumnResizing,
DragDropContext, TableColumnReordering,
} from '@devexpress/dx-react-grid-material-ui';
import {connect} from 'react-redux';
import * as actionTypes from '../../store/actions';
class PeerTab extends React.Component {
constructor(props) {
super(props);
this.state = { //rows are stored in redux they are sent over from the server
columns: [
{ name: 'PeerID', title: 'Peer ID' },
{ name: 'IP', title: 'IP Address'},
//{ name: 'Country', title: 'Country of Origin'}, //TODO map IP to country
{ name: 'Port', title: 'Port'},
{ name: 'Source', title: 'Source'}, //T=Tracker, I=Incoming, Hg=DHTGetPeers, Ha=DHTAnnouncePeer, X=PEX
{ name: 'SupportsEncryption', title: 'Supports Encryption'},
],
sorting: [],
columnOrder: ['PeerID', 'IP', 'Port', 'Source', 'SupportsEncryption'],
columnWidths: {PeerID: 250, IP: 150, Port: 100, Source: 150, SupportsEncryption: 150},
};
this.changeColumnOrder = columnOrder => this.setState({columnOrder});
this.changeColumnWidths = columnWidths => this.setState({columnWidths});
this.changeSorting = sorting => this.setState({sorting});
}
render() {
return (
<Grid rows={this.props.peerList} columns={this.state.columns}>
<SortingState sorting={this.state.sorting} onSortingChange={this.changeSorting} />
<LocalSorting />
<DragDropContext />
<VirtualTableView height={350}/>
<TableColumnResizing columnWidths={this.state.columnWidths} onColumnWidthsChange={this.changeColumnWidths}/>
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
<TableHeaderRow allowSorting allowResizing allowDragging />
</Grid>
);
}
}
const mapStateToProps = state => {
return {
selectionHashes: state.selectionHashes,
peerList: state.peerList,
};
}
export default connect(mapStateToProps)(PeerTab)

View File

@@ -0,0 +1,86 @@
import React from 'react';
import PropTypes from 'prop-types';
import 'typeface-roboto'; // contains the font for material UI
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Tabs, { Tab } from 'material-ui/Tabs';
import GeneralTab from './Tabs/generalTab';
import PeerTab from './Tabs/peerTab';
import FileTab from './Tabs/fileTab';
//Redux
import {connect} from 'react-redux';
import * as actionTypes from '../store/actions'
function TabContainer(props) {
return <div style={{ padding: 8 * 3 }}>{props.children}</div>;
}
TabContainer.propTypes = {
children: PropTypes.node.isRequired,
};
const styles = theme => ({
root: {
// flexGrow: 1,
// marginTop: theme.spacing.unit * 3,
//backgroundColor: theme.palette.background.paper,
backgroundColor: '#e5e5e5',
height: '100%',
boxShadow: '0 0 20px #000',
},
});
class BasicTabs extends React.Component {
handleChange = (event, value) => {
//this.setState({ value });
this.props.changeTab(value)
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<div className="DragHandle"> {/* making the appbar draggable */}
<AppBar position="static">
<Tabs value={this.props.selectedTab} onChange={this.handleChange}>
<Tab label="General"/>
<Tab label="Peers"/>
<Tab label="Files"/>
<Tab label="Speed"/>
<Tab label="Logger" href="#basic-tabs"/>
</Tabs>
</AppBar>
</div>
{this.props.selectedTab === 0 && <TabContainer><GeneralTab /></TabContainer>}
{this.props.selectedTab === 1 && <TabContainer><PeerTab /></TabContainer>}
{this.props.selectedTab === 2 && <TabContainer><FileTab /></TabContainer>}
{this.props.selectedTab === 3 && <TabContainer>Speed</TabContainer>}
{this.props.selectedTab === 4 && <TabContainer>Logger</TabContainer>}
</div>
);
}
}
BasicTabs.propTypes = {
classes: PropTypes.object.isRequired,
};
const mapStateToProps = state => {
return {
selectedTab: state.selectedTab,
};
}
const mapDispatchToProps = dispatch => {
return {
changeTab: (selectedTab) => dispatch({type: actionTypes.SELECTED_TAB, selectedTab }),
}
}
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(BasicTabs));

View File

@@ -0,0 +1,9 @@
.button {
font-size: '60px';
}
.padding {
display: inline-block;
padding-top: '10px';
padding-left: '10px';
}

View File

@@ -0,0 +1,52 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TableCell } from 'material-ui';
import { withStyles } from 'material-ui/styles';
const styles = theme => ({
progressBarCell: {
paddingLeft: theme.spacing.unit,
paddingRight: theme.spacing.unit,
borderBottom: `1px solid ${theme.palette.text.lightDivider}`,
},
progressBar: {
backgroundColor: theme.palette.primary[300],
float: 'left',
height: theme.spacing.unit,
whiteSpace: 'nowrap',
},
progressText: {
display: 'inline-block',
fontSize: '1em',
textAlign: 'right',
verticalAlign: 'text-top',
fontSize: '12px',
fontWeight: 'bold',
margin: '5px',
whiteSpace: 'nowrap',
}
});
export const ProgressBarCellBase = ({ value, classes, style }) => (
<TableCell
className={classes.progressBarCell}
style={style}
>
<div
className={classes.progressBar}
style={{ width: `${value}%` }}
title={`${value.toFixed(1)}%`}
/><div className={classes.progressText}>{value}</div>
</TableCell>
);
ProgressBarCellBase.propTypes = {
value: PropTypes.number.isRequired,
classes: PropTypes.object.isRequired,
style: PropTypes.object,
};
ProgressBarCellBase.defaultProps = {
style: {},
};
export const ProgressBarCell = withStyles(styles, { name: 'ProgressBarCell' })(ProgressBarCellBase);

View File

@@ -0,0 +1,136 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import { withStyles } from 'material-ui/styles';
import PropTypes from 'prop-types';
import List, {
ListItem,
ListItemIcon,
ListItemSecondaryAction,
ListItemText,
} from 'material-ui/List';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import InsertLinkIcon from 'material-ui-icons/Link';
import ReactTooltip from 'react-tooltip'
import Icon from 'material-ui/Icon';
import IconButton from 'material-ui/IconButton';
import RSSTorrentIcon from 'material-ui-icons/RssFeed';
import AddRSSIcon from 'material-ui-icons/AddCircle';
import DeleteIcon from 'material-ui-icons/Delete';
//Redux
import {connect} from 'react-redux';
import * as actionTypes from '../../../store/actions';
const button = {
fontSize: '60px',
paddingRight: '20px',
paddingLeft: '20px',
}
const smallButton = {
width: '36px',
height: '36px',
padding: '5px',
}
const rssInput = {
width: '90%',
paddingRight: '10px',
}
const inlineStyle = {
display: 'inline-block',
backdrop: 'static',
}
class RSSFeedList extends React.Component {
state = {
testRSSFeeds: [],
showList: false,
selectedIndex: 0,
};
showRSSFiles = (key) => {
let RSSTorrentsRequest = {
messageType: "rssTorrentsRequest",
Payload: [this.props.RSSList[key].RSSURL]
}
ws.send(JSON.stringify(RSSTorrentsRequest))
this.setState({selectedIndex: key}) //setting our selected index for styling
console.log("RSSFEED", key, "sending message", JSON.stringify(RSSTorrentsRequest))
}
getStyle = (index) => {
console.log("SettingStye", selectedIndex, index)
if (selectedIndex == index){
console.log("Returning activestyle")
style = "{{backgroundColor: '#80b3ff'}}"
return style
}
style = "{{backgroundColor: '#f44295'}}"
return style
}
deleteRSSFeed = (key) => {
let RSSURLDelete = {
messageType: "deleteRSSFeed",
Payload: [this.props.RSSList[key]]
}
console.log("Deleting THIS", this.props.RSSList[key])
//ws.send(JSON.stringify(RSSURLDelete));
}
render() {
//const { classes, onRequestClose, handleRequestClose, handleSubmit } = this.props;
if (this.props.RSSList.length > 0 && this.state.showList == false){
console.log("Setting list to show....")
this.setState({showList: true})
}
return (
<div style={inlineStyle}>
{this.state.showList == true && //if we have any rss torrent feeds then display them in list }
<List dense>
{this.props.RSSList.map((RSSFeed, index) => {
return (
<ListItem button={true} onClick={() => this.showRSSFiles(index)} key={index}>
<ListItemText primary={RSSFeed.RSSName} />
<ListItemSecondaryAction>
<IconButton key={index} onClick={() => this.deleteRSSFeed(index)} aria-label="Delete">
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
)})}
</List>
}
</div>
);
}
};
const mapStateToProps = state => {
return {
RSSList: state.RSSList,
};
}
const mapDispatchToProps = dispatch => {
return {
rssModalOpenState: (RSSModalOpen) => dispatch({type: actionTypes.RSS_MODAL_OPEN_STATE, RSSModalOpen}), //sending modal state to backendwebsocket so we can update RSS lists
}
}
export default connect(mapStateToProps, mapDispatchToProps)(RSSFeedList)

View File

@@ -0,0 +1,187 @@
import React from 'react';
import ReactDOM from 'react-dom';
//css for react grid
import '../../../../node_modules/react-grid-layout/css/styles.css';
import '../../../../node_modules/react-resizable/css/styles.css';
//react-grid for layout
import RGL, { WidthProvider } from 'react-grid-layout';
import PropTypes from 'prop-types';
import _ from 'lodash';
//Redux
import {connect} from 'react-redux';
import * as actionTypes from '../../../store/actions';
//interior items
import TextField from 'material-ui/TextField';
import { withStyles } from 'material-ui/styles';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import ReactTooltip from 'react-tooltip'
import Icon from 'material-ui/Icon';
import RSSTorrentIcon from 'material-ui-icons/RssFeed';
import AddRSSIcon from 'material-ui-icons/AddCircle';
import RSSFeedList from './RSSFeedList';
import RSSTorrentList from './RSSTorrentList';
import IconButton from 'material-ui/IconButton';
import Button from 'material-ui/Button';
const ReactGridLayout = WidthProvider(RGL);
const background = {
backgroundColor: '#e5e5e5',
boxShadow: '0 0 20px #000',
}
const button = {
fontSize: '60px',
paddingRight: '20px',
paddingLeft: '20px',
}
const smallButton = {
width: '36px',
height: '36px',
padding: '5px',
}
const rssInput = {
width: '90%',
paddingRight: '10px',
}
const inlineStyle = {
display: 'inline-block',
backdrop: 'static',
}
class RSSModalLayout extends React.Component {
static propTypes = {
onLayoutChange: PropTypes.func.isRequired
};
static defaultProps = {
className: "layout",
items: 4,
rowHeight: 100,
onLayoutChange: function() {},
cols: 6,
draggableCancel: '.NoDrag',
draggableHandle: '.DragHandle'
};
constructor(props) {
super(props);
var layout = [
{i: 'a', x: 0, y: 0, w: 6, h: 1, static: true},
{i: 'b', x: 0, y: 1, w: 1, h: 5, static: true},
{i: 'c', x: 1, y: 1, w: 5, h: 5, minW: 5, minH: 3, static: true},
];
this.state = { layout };
};
onLayoutChange(layout) {
this.props.onLayoutChange(layout);
}
handleRSSModalClose = () => {
let closeState = false
this.props.rssModalOpenState(closeState)
}
handleAddRSSFeed = () => {
this.setState({ textValue: "Clear"}) //clearing out the text submitted
let RSSURLSubmit = {
messageType: "addRSSFeed",
Payload: [this.state.textValue]
}
ws.send(JSON.stringify(RSSURLSubmit));
let RSSRequest = {
messageType: "rssFeedRequest",
}
ws.send(JSON.stringify(RSSRequest)) //Immediatly request an update of the feed when you add a new URL
}
setTextValue = (event) => {
this.setState({ textValue: event.target.value });
}
componentWillReceiveProps (nextProps) {
console.log("nextprops", nextProps, "Modal", nextProps.RSSModalOpen)
}
componentWillMount () {
console.log("Mounting grid")
}
render() {
return (
<div style={inlineStyle}>
<DialogContent>
<ReactGridLayout layout={this.state.layout} onLayoutChange={this.onLayoutChange}
{...this.props}>
<div key="a" sytle={background} className="DragHandle">
<TextField
style={rssInput}
autoFocus
margin="dense"
id="name"
label="Add New RSS URL"
type="text"
placeholder="Enter RSS URL Here.."
onChange={this.setTextValue}
/>
<IconButton onClick={this.handleAddRSSFeed} color="primary" data-tip="Add RSS Feed" style={smallButton} aria-label="Add RSS Feeds">
<ReactTooltip place="top" type="light" effect="float" />
<AddRSSIcon />
</IconButton>
</div>
<div key="b" style={background} className="DragHandle">
<RSSFeedList />
</div>
<div key="c" style={background} className="DragHandle">
<RSSTorrentList />
</div>
</ReactGridLayout>
</DialogContent>
<DialogActions>
<Button onClick={this.handleRSSModalClose} color="primary">
Close
</Button>
</DialogActions>
</div>
);
}
};
//module.exports = RSSModalLayout;
const mapStateToProps = state => {
return {
RSSList: state.RSSList,
RSSModalOpen: state.RSSModalOpen,
};
}
const mapDispatchToProps = dispatch => {
return {
rssModalOpenState: (RSSModalOpen) => dispatch({type: actionTypes.RSS_MODAL_OPEN_STATE, RSSModalOpen}),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(RSSModalLayout)

View File

@@ -0,0 +1,119 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import {
SortingState, LocalSorting, VirtualTableLayout, SelectionState,
} from '@devexpress/dx-react-grid';
import {
Grid, TableHeaderRow, PagingPanel, VirtualTableView, TableColumnResizing,
DragDropContext, TableColumnReordering, TableSelection,
} from '@devexpress/dx-react-grid-material-ui';
import {connect} from 'react-redux';
import * as actionTypes from '../../../store/actions';
const tableStyle = {
}
class RSSTorrentList extends React.Component {
constructor(props) {
super(props);
this.state = { //rows are stored in redux they are sent over from the server
columns: [
{ name: 'TorrentName', title: 'Title'},
{ name: 'TorrentLink', title: 'Magnet Link' },
{ name: 'PublishDate', title: 'Date Published'},
],
sorting: [],
columnOrder: ['TorrentName', 'TorrentLink', 'PublishDate'],
columnWidths: {TorrentName: 450, TorrentLink: 650, PublishDate: 200},
fileSelection: [],
selected: [],
};
this.changeColumnOrder = columnOrder => this.setState({columnOrder});
this.changeColumnWidths = columnWidths => this.setState({columnWidths});
this.changeSorting = sorting => this.setState({sorting});
}
changeSelection = (selection) => {
console.log("TorrentList is changing selection now", selection)
this.setState({selected: selection})
if (selection.length > 0) { //if selection is empty buttons will be default and selectionHashes will be blanked out and pushed to redux
console.log("Getting the selected Rows")
const selectedRows = [] //array of all the selected Rows
selection.forEach(element => {
selectedRows.push(this.props.RSSTorrentList[element]) //pushing the selected rows out of torrentlist
});
this.setState({fileSelection: selectedRows})
}
}
sendMagnetLinks = () => {
let sendMagnetLinks = []
this.state.fileSelection.forEach(element => { //fileselection contains the currently selected rows
console.log("element", element)
sendMagnetLinks.push(element.TorrentLink)
})
let magnetLinkSubmit = {
MessageType: "magnetLinkSubmit",
Payload: sendMagnetLinks,
}
console.log(JSON.stringify(magnetLinkSubmit))
ws.send(JSON.stringify(magnetLinkSubmit))
}
componentWillReceiveProps () {
console.log("New torrentlist", this.props.RSSTorrentList)
}
render() {
return (
//Buttons here
<div>
<Button raised color="primary" onClick={this.sendMagnetLinks}>
Download Torrents
</Button>
<Grid rows={this.props.RSSTorrentList} columns={this.state.columns}>
<SortingState sorting={this.state.sorting} onSortingChange={this.changeSorting} />
<LocalSorting />
<DragDropContext />
<SelectionState onSelectionChange={this.changeSelection} selection={this.state.selection}/>
<VirtualTableView height={500} />
<TableColumnResizing columnWidths={this.state.columnWidths} onColumnWidthsChange={this.changeColumnWidths}/>
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
<TableSelection selectByRowClick highlightSelected />
<TableHeaderRow allowSorting allowResizing allowDragging />
</Grid>
</div>
);
}
}
const mapStateToProps = state => {
return {
selectionHashes: state.selectionHashes,
RSSTorrentList: state.RSSTorrentList,
};
}
export default connect(mapStateToProps)(RSSTorrentList)

View File

@@ -0,0 +1,93 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import { withStyles } from 'material-ui/styles';
import PropTypes from 'prop-types';
import List, {
ListItem,
ListItemIcon,
ListItemSecondaryAction,
ListItemText,
} from 'material-ui/List';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import InsertLinkIcon from 'material-ui-icons/Link';
import ReactTooltip from 'react-tooltip'
import Icon from 'material-ui/Icon';
import IconButton from 'material-ui/IconButton';
import RSSTorrentIcon from 'material-ui-icons/RssFeed';
import AddRSSIcon from 'material-ui-icons/AddCircle';
import RSSModalLayout from './RSSModalLayout'
//Redux
import {connect} from 'react-redux';
import * as actionTypes from '../../../store/actions';
const button = {
fontSize: '60px',
paddingRight: '20px',
paddingLeft: '20px',
}
const inlineStyle = {
display: 'inline-block',
backdrop: 'static',
}
class AddRSSModal extends React.Component {
componentDidMount () { //Immediatly request an update of the feed when loading app
let RSSRequest = {
messageType: "rssFeedRequest",
}
ws.send(JSON.stringify(RSSRequest))
}
rssModalOpenState = () => {
console.log("Opening RSS Modal")
this.props.rssModalOpenState(true)
}
render() {
const { classes, onRequestClose, handleRequestClose, handleSubmit } = this.props;
return (
<div style={inlineStyle}>
<IconButton onClick={this.rssModalOpenState} color="primary" data-tip="Add RSS URL" style={button} aria-label="RSS Feeds">
<ReactTooltip place="top" type="light" effect="float" />
<RSSTorrentIcon />
</IconButton>
<Dialog fullScreen open={this.props.RSSModalOpen} onRequestClose={this.handleRequestClose}>
<DialogTitle>Manage RSS Feeds</DialogTitle>
<RSSModalLayout />
</Dialog>
</div>
);
}
};
const mapStateToProps = state => {
return {
RSSModalOpen: state.RSSModalOpen,
};
}
const mapDispatchToProps = dispatch => {
return {
rssModalOpenState: (RSSModalOpen) => dispatch({type: actionTypes.RSS_MODAL_OPEN_STATE, RSSModalOpen}),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(AddRSSModal)

View File

@@ -0,0 +1,70 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import { withStyles } from 'material-ui/styles';
import PropTypes from 'prop-types';
import Dialog, {
DialogContent,
DialogTitle,
} from 'material-ui/Dialog';
//import InsertLinkIcon from 'material-ui-icons/Link';
import ReactTooltip from 'react-tooltip'
//import Icon from 'material-ui/Icon';
import AddIcon from 'material-ui-icons/AddBox';
import IconButton from 'material-ui/IconButton';
//import Dropzone from 'react-dropzone'; //the File drop acceptor
//const request = require('superagent');
const button = {
fontSize: '60px',
paddingRight: '20px',
paddingLeft: '20px',
}
const inlineStyle = {
display: 'inline-block',
}
export default class addTorrentFilePopup extends React.Component {
state = {
open: false,
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleRequestClose = () => {
this.setState({ open: false });
};
setTextValue = (event) => {
this.setState({textValue: event.target.value});
}
render() {
const { classes, onRequestClose, handleRequestClose, handleSubmit } = this.props;
return (
<div style={inlineStyle}>
<IconButton onClick={this.handleClickOpen} color="primary" data-tip="Add Torrent File" style={button} centerRipple aria-label="Add Torrent File" >
<ReactTooltip place="top" type="light" effect="float" />
<AddIcon />
</IconButton>
<Dialog open={this.state.open} onRequestClose={this.handleRequestClose} onEscapeKeyUp={this.handleRequestClose} maxWidth="md">
<DialogTitle>Add Torrent File</DialogTitle>
<DialogContent>
<form encType="multipart/form-data" method="post" action="/uploadTorrent">
<input name="fileTest" type="file" /><p />
<input type="submit" value="submit" />
</form>
</DialogContent>
</Dialog>
</div>
);
}
};

View File

@@ -0,0 +1,101 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import { withStyles } from 'material-ui/styles';
import PropTypes from 'prop-types';
import Dialog, {
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from 'material-ui/Dialog';
import InsertLinkIcon from 'material-ui-icons/Link';
import ReactTooltip from 'react-tooltip'
import Icon from 'material-ui/Icon';
import IconButton from 'material-ui/IconButton';
const button = {
fontSize: '60px',
paddingRight: '20px',
paddingLeft: '20px',
}
const inlineStyle = {
display: 'inline-block',
backdrop: 'static',
}
export default class addTorrentPopup extends React.Component {
state = {
open: false,
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleRequestClose = () => {
this.setState({ open: false });
};
handleSubmit = () => {
this.setState({ open: false });
//let magnetLinkSubmit = this.state.textValue;
let magnetLinkMessage = {
messageType: "magnetLinkSubmit",
Payload: [this.state.textValue]
}
console.log("Sending magnet link: ", magnetLinkMessage);
ws.send(JSON.stringify(magnetLinkMessage));
}
setTextValue = (event) => {
this.setState({textValue: event.target.value});
}
render() {
const { classes, onRequestClose, handleRequestClose, handleSubmit } = this.props;
return (
<div style={inlineStyle}>
<IconButton onClick={this.handleClickOpen} color="primary" data-tip="Add Magnet Link" style={button} centerRipple aria-label="Add Magnet Link" >
<ReactTooltip place="top" type="light" effect="float" />
<InsertLinkIcon />
</IconButton>
<Dialog open={this.state.open} onRequestClose={this.handleRequestClose}>
<DialogTitle>Add Magnet Link</DialogTitle>
<DialogContent>
<DialogContentText>
Add a Magnet Link here and hit submit to add torrent...
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
label="Magnet Link"
type="text"
placeholder="Enter Magnet Link Here"
fullWidth
onChange={this.setTextValue}
/>
</DialogContent>
<DialogActions>
<Button onClick={this.handleRequestClose} color="primary">
Cancel
</Button>
<Button onClick={this.handleSubmit} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
</div>
);
}
};

View File

@@ -0,0 +1,161 @@
import React from 'react';
import PropTypes from 'prop-types';
import 'typeface-roboto'; // contains the font for material UI
import { withStyles } from 'material-ui/styles';
import Icon from 'material-ui/Icon';
import IconButton from 'material-ui/IconButton';
import AddTorrentLinkPopup from './Modals/addTorrentLinkModal';
import AddTorrentFilePopup from './Modals/addTorrentFileModal';
import AddRSSModal from './Modals/RSSModal/addRSSModal';
import StartTorrentIcon from 'material-ui-icons/PlayArrow';
//import PauseTorrentIcon from 'material-ui-icons/Pause';
import StopTorrentIcon from 'material-ui-icons/Stop';
import DeleteTorrentIcon from 'material-ui-icons/Delete';
import RSSTorrentIcon from 'material-ui-icons/RssFeed';
import SettingsIcon from 'material-ui-icons/Settings';
import ReactTooltip from 'react-tooltip'
import DeleteIcon from 'material-ui-icons/Delete';
import AddShoppingCartIcon from 'material-ui-icons/AddShoppingCart';
import BackendSocket from '../BackendComm/backendWebsocket';
//Redux
import {connect} from 'react-redux';
import * as actionTypes from '../store/actions'
const styles = theme => ({
button: {
margin: theme.spacing.unit,
fontSize: '60px',
},
input: {
display: 'none',
},
paddingTest: {
display: 'inline-block'
},
padding: {
paddingTop: '10px',
paddingLeft: '10px',
},
verticalDivider: {
borderLeft: '2px solid grey',
padding: '20px',
height: '40px',
position: 'absolute',
display: 'inline-block',
paddingRight: '30px',
paddingLeft: '30px',
},
background: {
backgroundColor: theme.palette.background.paper,
}
});
class IconButtons extends React.Component {
constructor(props){
super(props);
}
startTorrent = () => {
console.log("Starting Torrents", this.props.selectionHashes)
let startTorrentHashes = {
MessageType: "startTorrents",
Payload: this.props.selectionHashes,
}
//console.log("Peers tab information requested", peerListHashes)
ws.send(JSON.stringify(startTorrentHashes))
this.props.setButtonState(this.props.selection) //TODO this currently just forces a button refresh, should be a better way to do this
}
stopTorrent = () => {
let stopTorrentHashes = {
MessageType: "stopTorrents",
Payload: this.props.selectionHashes,
}
console.log("Stopping Torrents", stopTorrentHashes)
ws.send(JSON.stringify(stopTorrentHashes))
this.props.setButtonState(this.props.selection) //TODO this currently just forces a button refresh, should be a better way to do this
}
deleteTorrent = () => {
let deleteTorrentHashes = {
MessageType: "deleteTorrents",
Payload: this.props.selectionHashes,
}
console.log("Deleting Torrents", deleteTorrentHashes)
ws.send(JSON.stringify(deleteTorrentHashes))
this.props.setButtonState(this.props.selection) //TODO this currently just forces a button refresh, should be a better way to do this
}
render() {
const { classes } = this.props;
return (
<div className={classes.padding}>
<AddTorrentFilePopup />
<AddTorrentLinkPopup />
<div className={classes.verticalDivider}></div>
<IconButton color={this.props.buttonState[0].startButton} data-tip="Start Torrent" className={classes.button} aria-label="Start Torrent" onClick={this.startTorrent}>
<ReactTooltip place="top" type="light" effect="float" />
<StartTorrentIcon />
</IconButton>
{/* <IconButton color={this.props.buttonState[0].pauseButton} data-tip="Pause Torrent" className={classes.button} aria-label="Pause Torrent">
<ReactTooltip place="top" type="light" effect="float" />
<PauseTorrentIcon />
</IconButton> */}
<IconButton color={this.props.buttonState[0].stopButton} data-tip="Stop Torrent" className={classes.button} onClick={this.stopTorrent} aria-label="Stop Torrent">
<ReactTooltip place="top" type="light" effect="float" />
<StopTorrentIcon />
</IconButton>
<IconButton color={this.props.buttonState[0].deleteButton} data-tip="Delete Torrent" className={classes.button} onClick={this.deleteTorrent} aria-label="Delete Torrent">
<ReactTooltip place="top" type="error" effect="float" />
<DeleteTorrentIcon />
</IconButton>
<div className={classes.verticalDivider}></div>
<AddRSSModal />
<IconButton color="primary" data-tip="Settings" className={classes.button} aria-label="Settings">
<ReactTooltip place="top" type="light" effect="float" />
<SettingsIcon />
</IconButton>
<div className={classes.verticalDivider}></div>
<BackendSocket />
</div>
);
}
}
IconButtons.propTypes = {
classes: PropTypes.object.isRequired,
};
const mapStateToProps = state => {
return {
buttonState: state.buttonState,
selection: state.selection,
selectionHashes: state.selectionHashes,
};
}
const mapDispatchToProps = dispatch => {
return {
setButtonState: (buttonState) => dispatch({type: actionTypes.SET_BUTTON_STATE, buttonState}),
}
}
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(IconButtons))

View File

@@ -0,0 +1,85 @@
import React from 'react';
import ReactDOM from 'react-dom';
//css for react grid
import '../node_modules/react-grid-layout/css/styles.css';
import '../node_modules/react-resizable/css/styles.css';
//react-grid for layout
import RGL, { WidthProvider } from 'react-grid-layout';
import PropTypes from 'prop-types';
import _ from 'lodash';
//Redux
import {createStore} from 'redux';
import {Provider} from 'react-redux';
import reducer from './store/reducer';
//Menu and torrentlist imports
import TopMenu from './TopMenu/topMenu';
import BottomMenu from './BottomMenu/bottomMenu';
import LeftMenu from './leftMenu/leftMenu';
import TorrentList from './torrentlist';
const reduxStore = createStore(reducer);
const ReactGridLayout = WidthProvider(RGL);
var background = {
backgroundColor: '#e5e5e5',
boxShadow: '0 0 20px #000',
}
class BasicLayout extends React.PureComponent {
static propTypes = {
onLayoutChange: PropTypes.func.isRequired
};
static defaultProps = {
className: "layout",
items: 4,
rowHeight: 100,
onLayoutChange: function() {},
cols: 6,
draggableCancel: '.NoDrag',
draggableHandle: '.DragHandle'
};
constructor(props) {
super(props);
var layout = [
{i: 'a', x: 0, y: 0, w: 6, h: 1, static: true},
{i: 'b', x: 0, y: 1, w: 1, h: 9, static: true},
{i: 'c', x: 1, y: 1, w: 5, h: 5, minW: 5, minH: 3, static: true},
{i: 'd', x: 1, y: 6, w: 5, h: 4, minW: 5, minH: 1, static: true}
];
this.state = { layout };
}
onLayoutChange(layout) {
this.props.onLayoutChange(layout);
}
render() {
return (
<ReactGridLayout layout={this.state.layout} onLayoutChange={this.onLayoutChange}
{...this.props}>
<div key="a" style={background} className="DragHandle"><TopMenu /></div>
<div key="b" style={background} className="DragHandle"><LeftMenu /></div>
<div key="c" style={background} className="DragHandle"><TorrentList /></div>
<div key="d"><BottomMenu /></div>
</ReactGridLayout> //returning our 4 grids
);
}
};
module.exports = BasicLayout;
//if (require.main === module) {
// require('../test-hook.jsx')(module.exports);
//}
ReactDOM.render(
<Provider store={reduxStore}><BasicLayout /></Provider>, //wrapping redux around our app
document.getElementById('app')
);

View File

@@ -0,0 +1,174 @@
import React from 'react';
import PropTypes from 'prop-types';
import 'typeface-roboto'; // contains the font for material UI
import { withStyles } from 'material-ui/styles';
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
import Divider from 'material-ui/Divider';
import DownloadingTorrentsIcon from 'material-ui-icons/FileDownload'
import UploadingTorrentsIcon from 'material-ui-icons/FileUpload'
import ActiveTorrentsIcon from 'material-ui-icons/SwapVert'
import AllTorrentsIcon from 'material-ui-icons/AllInclusive'
//react redux
import {connect} from 'react-redux';
import * as actionTypes from './store/actions';
//TODO, clean up the goddamn variable names you are all over the place
const styles = theme => ({
root: {
width: '100%',
maxWidth: 360,
backgroundColor: '#e5e5e5',
},
icons: {
width: '40px',
height: '40px',
},
inactiveIcon: {
width: '40px',
height: '40px',
color: 'red',
},
active: {
backgroundColor: '#80b3ff',
}
});
class SimpleList extends React.Component {
constructor(props){
super(props);
const { classes } = this.props;
this.state = {
allTorrentsClass: classes.active,
downloadingClass: '',
seedingClass: '',
activeTorrentsClass: '',
completedTorrentsClass: '',
allID: "All",
downloadingID: "Downloading",
seedingID: "Seeding",
activeID: "Active",
completedID: "Completed",
}
}
setActiveElement = (listItem) => {
}
setFilter = (filterState, id) => {
const { classes } = this.props;
filterState = [{columnName: 'Status', value: filterState}]
this.props.changeFilter(filterState)//dispatch to redux
console.log("Switching filters classes", id)
switch (id){ //TODO.. there has to be a better fucking way to do this
case "All":
this.state.allTorrentsClass = classes.active
this.state.downloadingClass = ''
this.state.seedingClass = ''
this.state.activeTorrentsClass = ''
this.state.completedTorrentsClass = ''
break
case "Downloading":
console.log("Downloading...")
this.state.downloadingClass = classes.active
this.state.allTorrentsClass = ''
this.state.seedingClass = ''
this.state.activeTorrentsClass = ''
this.state.completedTorrentsClass = ''
break
case "Seeding":
this.state.seedingClass = classes.active
this.state.allTorrentsClass = ''
this.state.downloadingClass = ''
this.state.activeTorrentsClass = ''
this.state.completedTorrentsClass = ''
break
case "Active":
this.state.activeTorrentsClass = classes.active
this.state.allTorrentsClass = ''
this.state.downloadingClass = ''
this.state.seedingClass = ''
this.state.completedTorrentsClass = ''
break
case "Completed":
this.state.completedTorrentsClass = classes.active
this.state.allTorrentsClass = ''
this.state.downloadingClass = ''
this.state.seedingClass = ''
this.state.activeTorrentsClass = ''
break
}
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<List dense>
<ListItem dense className={this.state.allTorrentsClass} button onClick={ () => this.setFilter('', this.state.allID)}>
<ListItemIcon className={classes.icons} >
<AllTorrentsIcon />
</ListItemIcon>
<ListItemText primary="All Torrents" />
</ListItem>
<ListItem className={this.state.downloadingClass} button={true} onClick={ () => this.setFilter('Downloading', this.state.downloadingID)}>
<ListItemIcon className={classes.icons}>
<DownloadingTorrentsIcon />
</ListItemIcon>
<ListItemText primary="Downloading Torrents" />
</ListItem>
<ListItem className={this.state.seedingClass} button={true} onClick={ () => this.setFilter('Seeding', this.state.seedingID)}>
<ListItemIcon className={classes.icons}>
<UploadingTorrentsIcon />
</ListItemIcon>
<ListItemText primary="Seeding Torrents" />
</ListItem>
{/* <ListItem className={this.state.activeTorrentsClass} button={true} onClick={ () => this.setFilter('Active', this.state.activeID)}>
<ListItemIcon className={classes.icons}>
<ActiveTorrentsIcon />
</ListItemIcon>
<ListItemText primary="Active Torrents" />
</ListItem> */}
<ListItem className={this.state.completedTorrentsClass} button={true} onClick={ () => this.setFilter('Completed', this.state.completedID)}>
<ListItemIcon className={classes.inactiveIcon}>
<ActiveTorrentsIcon />
</ListItemIcon>
<ListItemText primary="Completed Torrents" />
</ListItem>
</List>
<Divider />
</div>
);
}
}
SimpleList.propTypes = {
classes: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => {
return {
filter: state.filter
};
}
const mapDispatchToProps = dispatch => {
return {
changeFilter: (filter) => dispatch({type: actionTypes.CHANGE_FILTER, filter: filter})
}
}
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(SimpleList));

View File

@@ -0,0 +1,13 @@
export const SORTLIST = 'SORTLIST';
export const CHANGE_SELECTION = 'CHANGE_SELECTION';
export const CHANGE_FILTER = 'CHANGE_FILTER';
export const TORRENT_LIST = 'TORRENT_LIST';
export const SET_BUTTON_STATE = 'BUTTON_STATE';
export const SELECTION_HASHES = 'SELECTION_HASHES';
export const SELECTED_TAB = 'SELECTED_TAB';
export const PEER_LIST = 'PEER_LIST';
export const FILE_LIST = 'FILE_LIST';
export const CHANGE_FILE_SELECTION = 'CHANGE_FILE_SELECTION';
export const NEW_RSS_FEED_STORE = 'NEW_RSS_FEED_STORE';
export const RSS_MODAL_OPEN_STATE = 'RSS_MODAL_OPEN_STATE';
export const RSS_TORRENT_LIST = 'RSS_TORRENT_LIST';

View File

@@ -0,0 +1,163 @@
import * as actionTypes from './actions';
const initialState = {
buttonStateDefault: [{startButton: "default", stopButton: "default", deleteButton: "default", fSeedButton: "default", fRecheckButton: "default"}],
buttonState: [{startButton: "default", stopButton: "default", deleteButton: "default", fSeedButton: "default", fRecheckButton: "default"}],
sorting: [],
selection: [],
selectionHashes: [],
filter: ["Status", ""],
columnName: "Status",
torrentList: [],
peerList: [],
fileList: [],
torrentDetailInfo: [],
selectedTab: 0,
RSSList: [],
RSSTorrentList: [],
RSSModalOpen: false,
}
const reducer = (state = initialState, action) => {
switch(action.type){
case actionTypes.CHANGE_SELECTION:
console.log("Change Selection", action.selection)
return {
...state,
peerList: [], //changing selection will purge out all of the old data
fileList: [],
selectionHashes: [],
selection: action.selection,
};
case actionTypes.NEW_RSS_FEED_STORE:
console.log("New RSS Feed Store", action.RSSList)
return {
...state,
RSSList: action.RSSList,
}
case actionTypes.RSS_TORRENT_LIST:
console.log("New RSS Torrent List IN REDUCER", action.RSSTorrentList)
return {
...state,
RSSTorrentList: action.RSSTorrentList,
}
case actionTypes.SELECTION_HASHES:
console.log("Selection hashes REDUX", action.selectionHashes)
return {
...state,
selectionHashes: action.selectionHashes,
};
case actionTypes.SORTLIST: //TODO do I even need this in redux?
console.log("List Sort", action.sorting)
return state;
case actionTypes.CHANGE_FILTER:
return {
...state,
filter: action.filter
};
case actionTypes.TORRENT_LIST:
return {
...state,
torrentList: action.torrentList,
};
case actionTypes.PEER_LIST:
return {
...state,
peerList: action.peerList
}
case actionTypes.FILE_LIST:
return {
...state,
fileList: action.fileList
}
case actionTypes.SELECTED_TAB:
return {
...state,
selectedTab: action.selectedTab
}
case actionTypes.RSS_MODAL_OPEN_STATE:
console.log("Setting RSS Modal State...", action.RSSModalOpen)
return {
...state,
RSSModalOpen: action.RSSModalOpen
}
case actionTypes.SET_BUTTON_STATE:
if (action.buttonState.length === 0) { //if selection is empty buttons will be default and selectionHashes will be blanked out and pushed to redux
let buttonStateFinal = state.buttonStateDefault //if no selection dispatch that to redux
return {
...state,
buttonState: buttonStateFinal
};
} else { // if we have selection continue on with logic to determine button state
const selectedRows = [] //array of all the selected Rows
action.buttonState.forEach(element => {
selectedRows.push(state.torrentList[element]) //pushing the selected rows out of torrentlist
});
let buttonStateTest = selectedRows.filter(element => { //TODO fix this bad mess... we literally just need to filter for stopped and go from there
let result = []
if (element.Status === "Downloading" || element.Status === "Awaiting Peers" || element.Status === "Seeding" || element.Status === "Completed"){
result.push(element.Status)
return result
}
})
let buttonStateTest2 = selectedRows.filter(element => element.Status === "Stopped")
if (buttonStateTest.length > 0 && buttonStateTest2.length === 0){
let buttonStateFinal = [{startButton: "default", stopButton: "primary", deleteButton: "accent", fSeedButton: "default", fRecheckButton: "primary"}]
return {
...state,
buttonState: buttonStateFinal
};
}
if (buttonStateTest.length === 0 && buttonStateTest2.length > 0){
let buttonStateFinal = [{startButton: "primary", stopButton: "default", deleteButton: "accent", fSeedButton: "default", fRecheckButton: "primary"}]
return {
...state,
buttonState: buttonStateFinal
};
}
if (buttonStateTest.length > 0 && buttonStateTest2.length > 0){
let buttonStateFinal = [{startButton: "primary", stopButton: "primary", deleteButton: "accent", fSeedButton: "default", fRecheckButton: "primary"}]
return {
...state,
buttonState: buttonStateFinal
};
}
}
return {
...state,
buttonState: buttonStateFinal
};
default:
return state;
};
console.log("no actiontypes found", action)
return state;
}
export default reducer;

View File

@@ -0,0 +1,184 @@
import React from 'react';
import ReactDOM from 'react-dom';
import styles from '../node_modules/react-bootstrap-table/dist/react-bootstrap-table-all.min.css';
import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
import Paper from 'material-ui/Paper';
import {
SortingState, LocalSorting, PagingState, VirtualTableLayout, SelectionState, FilteringState, LocalFiltering,
} from '@devexpress/dx-react-grid';
import {
Grid, TableHeaderRow, PagingPanel, VirtualTableView, VirtualTable, TableSelection, TableColumnResizing,
DragDropContext, TableColumnReordering,
} from '@devexpress/dx-react-grid-material-ui';
import { ProgressBarCell } from './CustomCells/progressBarCell';
//react redux
import {connect} from 'react-redux';
import * as actionTypes from './store/actions';
/* var torrentLinkSubmit = document.getElementById('torrentLinkSubmit');
var magnetLink = document.getElementById('magnetLink');
var myTextArea = document.getElementById("loggerData");
var torrentHash = document.getElementById("hash");
initialize an empty torrents field before update.
var torrentLinkSubmit = document.getElementById('torrentLinkSubmit');
var magnetLink = document.getElementById('magnetLink');
var myTextArea = document.getElementById("loggerData");
var torrentHash = document.getElementById("hash");
var torrentLinkSubmit = document.getElementById('torrentLinkSubmit');
var torrentLinkModal = document.getElementById('addTorrentLinkModal');
var btnTorrentLink = document.getElementById("addTorrentLink");
*/
function sendEvent(message)
{
ws.send(message);
console.log('Sending message... ', message)
}
class TorrentListTable extends React.Component {
constructor(props) {
super(props);
this.state = { //rows are stored in redux they are sent over from the server
columns: [
{ name: 'TorrentName', title: 'Torrent Name' },
{ name: 'DownloadedSize', title: 'Dl Size'},
{ name: 'Size', title: 'Size'},
{ name: 'PercentDone', title: 'Percent Done'},
{ name: 'Status', title: 'Status'},
{ name: 'DownloadSpeed', title: 'DL Speed'},
{ name: 'UploadSpeed', title: 'UL Speed'},
{ name: 'ActivePeers', title: 'Active Peers' },
{ name: 'ETA', title: 'ETA'},
{ name: 'Ratio', title: 'Ratio'},
{ name: 'Availability', title: 'Availability'},
],
columnOrder: ['TorrentName', 'DownloadedSize', 'Size', 'PercentDone', 'Status', 'DownloadSpeed', 'UploadSpeed','ActivePeers', 'ETA', 'Ratio', 'Availability'],
columnWidths: {TorrentName: 250, DownloadedSize: 100, Size: 100, PercentDone: 175, Status: 150, DownloadSpeed: 100, UploadSpeed: 100, ActivePeers: 100, ETA: 100, Ratio: 75, Availability: 75},
prevSelection: [], //just used to pull data from cell (temp Prevcell holder), real selection is in Redux
pageSizes: [5, 10, 15, 0],
currentPage: 0,
};
this.changeColumnOrder = columnOrder => this.setState({columnOrder});
this.changeColumnWidths = columnWidths => this.setState({columnWidths});
this.changePageSize = pageSize => this.setState({ pageSize });
this.changeCurrentPage = currentPage => this.setState({ currentPage });
}
componentWillReceiveProps (nextProps){ //this is for setting the filter when the left menu activates a new filter
if (this.props.filter != nextProps.filter){
this.filterHandler(nextProps.filter)
}
//console.log("Recieving new props", nextProps.selection)
}
determineSelectionHashes = (selectedRows) => {
//console.log("CurrentSelectionHashes", this.props.selectionHashes)
let selectionHashes = [] //rebuilding our selection hashes from our currently selected rows
selectedRows.forEach(element => {
selectionHashes.push(element.TorrentHashString) //push the selection hash to the temp array
})
this.props.sendSelectionHashes(selectionHashes) //push the result to redux
}
changeSelection = (selection) => {
//console.log("TOrrentlist is changing selection now", selection)
this.props.changeSelection(selection) //dispatch selection to redux, also clear out anything tied to the old selection (peerlists, filelists, etc)
if (selection.length === 0) { //if selection is empty buttons will be default and selectionHashes will be blanked out and pushed to redux
this.props.setButtonState(selection) //if no selection dispatch that to redux
} else { // if we have selection continue on with logic to determine button state
const selectedRows = [] //array of all the selected Rows
selection.forEach(element => {
selectedRows.push(this.props.torrentList[element]) //pushing the selected rows out of torrentlist
});
//console.log("Determining selection hashses")
this.determineSelectionHashes(selectedRows) //pulling the torrent hashes for the selcted rows
this.props.setButtonState(selection)
}
}
filterHandler = (filter) => { //TODO, figure out how to do multiple filter
//console.log("Changing FIlter", filter)
if (filter.value ==="Active"){
console.log("This filter doesn't fucking work")
}
}
render() {
return (
<Paper>
<Grid rows={this.props.torrentList} columns={this.state.columns}>
<FilteringState filters={this.props.filter} />
<SortingState sorting={this.props.sorting} onSortingChange={this.props.changeSorting} />
<SelectionState onSelectionChange={this.changeSelection} selection={this.props.selection}/>
<LocalFiltering />
<LocalSorting />
<VirtualTableView height={530} tableCellTemplate={({ row, column, style }) => {
if (column.name === 'PercentDone') {
return (
<ProgressBarCell value={row.PercentDone * 100} style={style} />
);
}
return undefined;
}}/>
<DragDropContext />
<TableColumnResizing columnWidths={this.state.columnWidths} onColumnWidthsChange={this.changeColumnWidths}/>
<TableColumnReordering order={this.state.columnOrder} onOrderChange={this.changeColumnOrder} />
<TableSelection selectByRowClick highlightSelected />
<TableHeaderRow allowSorting allowResizing allowDragging />
</Grid>
</Paper>
);
}
}
const mapStateToProps = state => {
return {
filter: state.filter,
torrentList: state.torrentList,
buttonState: state.buttonState,
buttonStateDefault: state.buttonStateDefault, //all default
selectionHashes: state.selectionHashes,
selection: state.selection,
};
}
const mapDispatchToProps = dispatch => {
return {
changeSorting: (sorting) => dispatch({type: actionTypes.SORTLIST, sorting }),
changeSelection: (selection) => dispatch({type: actionTypes.CHANGE_SELECTION, selection}),
setButtonState: (buttonState) => dispatch({type: actionTypes.SET_BUTTON_STATE, buttonState}),
sendSelectionHashes: (selectionHashes) => dispatch({type: actionTypes.SELECTION_HASHES, selectionHashes}),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(TorrentListTable);