Add WIP connection screen

Does the basics but still needs to implement:

- Autoconnect
- "Connecting..." UI
- Disconnect by request
- Disconnect by circumstance
This commit is contained in:
Drew DeVault 2017-09-07 18:35:15 +09:00
parent 12c4936b68
commit 98d15e9dec
8 changed files with 116 additions and 21 deletions

View File

@ -49,6 +49,22 @@
background-position: left bottom; background-position: left bottom;
} }
.connection-overlay {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
.card {
min-width: 20rem;
}
}
input[type="text"], input[type="number"] { input[type="text"], input[type="number"] {
padding: 0.05rem 0.25rem; padding: 0.05rem 0.25rem;
border-radius: 0; border-radius: 0;
@ -127,7 +143,7 @@ select.form-control {
font-size: 0.9rem; font-size: 0.9rem;
} }
.form-check-input:only-child { fieldset .form-check-input:only-child {
position: absolute; position: absolute;
} }

5
src/actions/socket.js Normal file
View File

@ -0,0 +1,5 @@
export const SOCKET_CONNECTED = "SOCKET_CONNECTED";
export const SOCKET_DISCONNECTED = "SOCKET_DISCONNECTED";
export const socket_connected = () => ({ type: SOCKET_CONNECTED });
export const socket_disconnected = () => ({ type: SOCKET_DISCONNECTED });

View File

@ -10,29 +10,33 @@ import store, { history } from './store';
import scss from '../scss/main.scss'; import scss from '../scss/main.scss';
import { ws_init } from './socket'; import { ws_init } from './socket';
import { filter_subscribe } from './actions/filter_subscribe'; import { filter_subscribe } from './actions/filter_subscribe';
import { socket_connected, socket_disconnected } from './actions/socket';
import Nav from './ui/navigation'; import Nav from './ui/navigation';
import Main from './ui/main'; import Main from './ui/main';
import Connection from './ui/connection'; import Connection from './ui/connection';
const root = document.getElementById('root'); const root = document.getElementById('root');
ReactDOM.render(<Connection />, root);
ws_init(() => { export function initialize(uri) {
store.dispatch(filter_subscribe()); ws_init(uri, () => {
store.dispatch(filter_subscribe('server')); store.dispatch(socket_connected());
ReactDOM.render( store.dispatch(filter_subscribe());
<Provider store={store}> store.dispatch(filter_subscribe('server'));
<ConnectedRouter history={history}> });
<div> }
<Nav />
<div className="container"> ReactDOM.render(
<Main /> <Provider store={store}>
</div> <ConnectedRouter history={history}>
<div>
<Nav />
<div className="container">
<Main />
</div> </div>
</ConnectedRouter> </div>
</Provider>, root); </ConnectedRouter>
}); </Provider>, root);
navigator.registerProtocolHandler("magnet", navigator.registerProtocolHandler("magnet",
window.location.origin + "/add-torrent/%s", window.location.origin + "/add-torrent/%s",

View File

@ -1,5 +1,6 @@
import { combineReducers } from 'redux'; import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux' import { routerReducer } from 'react-router-redux'
import socket from './socket';
import selection from './selection'; import selection from './selection';
import subscribe from './subscribe'; import subscribe from './subscribe';
import filter_subscribe from './filter_subscribe'; import filter_subscribe from './filter_subscribe';
@ -11,6 +12,7 @@ import trackers from './trackers';
import pieces from './pieces'; import pieces from './pieces';
const root = combineReducers({ const root = combineReducers({
socket,
selection, selection,
subscribe, subscribe,
filter_subscribe, filter_subscribe,

12
src/reducers/socket.js Normal file
View File

@ -0,0 +1,12 @@
import { SOCKET_CONNECTED, SOCKET_DISCONNECTED } from '../actions/socket';
export default function socket(state = { connected: false }, action) {
switch (action.type) {
case SOCKET_CONNECTED:
return { ...state, connected: true };
case SOCKET_DISCONNECTED:
return { ...state, connected: false };
default:
return state;
}
}

View File

@ -35,8 +35,8 @@ function ws_recv(e) {
handler && handler(msg); handler && handler(msg);
} }
export function ws_init(cb) { export function ws_init(uri, cb) {
ws = new WebSocket("ws://127.0.0.1:8412"); ws = new WebSocket(uri);
ws.addEventListener("open", cb); ws.addEventListener("open", cb);
ws.addEventListener("message", ws_recv); ws.addEventListener("message", ws_recv);
ws.addEventListener("close", () => console.log("ws closed")); ws.addEventListener("close", () => console.log("ws closed"));

View File

@ -1,9 +1,60 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import {
Card,
CardHeader,
CardBlock,
FormGroup,
Label,
Input
} from 'reactstrap';
import { initialize } from '..';
export default class ConnectionOverlay extends Component {
constructor() {
super();
this.state = {
uri: "ws://127.0.0.1:8412",
autoconnect: false,
connecting: false
};
// TODO: "connecting..." UI
// TODO: autoconnect
// TODO: gracefully handle dis/reconnections
}
export default class Connection extends Component {
render() { render() {
const { uri, autoconnect } = this.state;
return ( return (
<p>Connecting...</p> <div className="connection-overlay">
<Card>
<CardHeader>Connect to synapse</CardHeader>
<CardBlock>
<FormGroup>
<Label for="socket-uri">Server URI</Label>
<Input
id="socket-uri"
value={uri}
onChange={e => this.setState({ uri: e.target.value })}
/>
</FormGroup>
<FormGroup>
<Label for="autoconnect" check>
<Input
id="autoconnect"
type="checkbox"
checked={autoconnect}
onChange={e => this.setState({ autoconnect: !autoconnect })}
check
/> Autoconnect to this server
</Label>
</FormGroup>
<button
className="btn btn-primary"
onClick={() => initialize(this.state.uri)}
>Connect</button>
</CardBlock>
</Card>
</div>
); );
} }
} }

View File

@ -1,11 +1,13 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Route, DefaultRoute } from 'react-router'; import { Route, DefaultRoute } from 'react-router';
import { connect } from 'react-redux';
import TorrentTable from './torrent_table'; import TorrentTable from './torrent_table';
import AddTorrent from './add_torrent'; import AddTorrent from './add_torrent';
import TorrentDetails from './torrent_details'; import TorrentDetails from './torrent_details';
import Server from './server'; import Server from './server';
import ConnectionOverlay from './connection';
export default class Main extends Component { class Main extends Component {
render() { render() {
return ( return (
<div className="row"> <div className="row">
@ -18,7 +20,10 @@ export default class Main extends Component {
<Route path="/torrents/:ids" component={TorrentDetails} /> <Route path="/torrents/:ids" component={TorrentDetails} />
<Route exact path="/" component={Server} /> <Route exact path="/" component={Server} />
</div> </div>
{this.props.socket.connected || <ConnectionOverlay />}
</div> </div>
); );
} }
} }
export default connect(state => ({ socket: state.socket }))(Main);