mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-25 03:23:24 -07:00
WebUI (#100)
* Object-Oriented base changes for web-ui prep * remove debug raise * optimize broadcast to serialize once * Implement WebUI socket, static assets, and classes - Still need to wrap logging functions and send output to UI - UI commands are successfully being sent to the server * GUI operational. Wrap logging functions, implement server address selection on GUI, automatically launch web browser when client websocket is served * Update MultiServer status when a user disconnects / reconnects * Implement colored item and hint checks, improve GUI readability * Fix improper formatting on received items * Update SNES connection status on disconnect / reconnect. Implement itemFound, prevent accidentally printing JS objects * Minor text change for itemFound * Fixed a very wrong comment * Fixed client commands not working, fixed un-helpful error messages appearing in GUI * Fix a bug causing a failure to connect to a multiworld server if a previously existing cached address was present and the client was loaded without an address passed in * Convert WebUI to React /w Redux. WebSocket communications not yet operational. * WebUI fully converted to React / Redux. - Websocket communication operational - Added a button to connect to the multiserver which appears only when a SNES is connected and a server connection is not active * Restore some features lost in WebUI - Restore (found) notification on hints if the item has already been obtained - Restore (x/y) indicator on received items, which indicates the number of items the client is waiting to receive from the client in a queue * Fix a grammatical UI big causing player names to show only an apostrophe when possessive * Add support for multiple SNES Devices, and switching between them * freeze support for client * make sure flask works when frozen * UI Improvements - Hint messages now actually show a found status via ✔ and ❌ emoji - Active player name is always a different color than other players (orange for now) - Add a toggle to show only entries relevant to the active player - Added a WidgetArea - Added a notes widget * Received items now marked as relevant * Include production build for deployment * Notes now survive a browser close. Minimum width applied to monitor to prevent CSS issues. * include webUi folder in setup.py * Bugfixes for Monitor - Fix a bug causing the monitor window to grow beyond it's intended content limit - Reduced monitor content limit to 200 items - Ensured each monitor entry has a unique key * Prevent eslint from yelling at me about stupid things * Add button to collapse sidebar, press enter on empty server input to disconnect on purpose * WebUI is now aware of client disconnect, message log limit increased to 350, fix !missing output * Update WebUI to v2.2.1 - Added color to WebUI for entrance-span - Make !missing show total count at bottom of list to match /missing behavior * Fix a bug causing clients version <= 2.2.0 to crash when anyone asks for a hint - Also fix a bug in the WebUI causing the entrance location to always show as "somewhere" * Update WebUI color palette (this cost me $50) * allow text console input alongside web-ui * remove Flask a bit overkill for what we're doing * remove jinja2 * Update WebUI to work with new hosting mechanism * with flask gone, we no longer need subprocess shenanigans * If multiple web ui clients try to run, at least present a working console * Update MultiClient and WebUI to handle multiple clients simultaneously. - The port on which the websocket for the WebUI is hosted is not chosen randomly from 5000 - 5999. This port is passed to the browser so it knows which MultiClient to connect to - Removed failure condition if a web server is already running, as there is no need to run more than one web server on a single system. If an exception is thrown while attempting to launch a web server, a check is made for the port being unavailable. If the port is unavailable, it probably means the user is launching a second MultiClient. A web browser is then opened with a connection to the correct webui_socket_port. - Add a /web command to the MultiClient to repoen the appropriate browser window and get params in case a user accidentally closes the tab * Use proper name for WebUI * move webui into /data with other data files * make web ui optional This is mostly for laptop users wanting to preserve some battery, should not be needed outside of that. * fix direct server start * re-add connection timer * fix indentation Co-authored-by: Chris <chris@legendserver.info>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
const SET_AVAILABLE_DEVICES = 'SET_AVAILABLE_DEVICES';
|
||||
|
||||
const setAvailableDevices = (devices) => ({
|
||||
type: SET_AVAILABLE_DEVICES,
|
||||
devices,
|
||||
});
|
||||
|
||||
export default setAvailableDevices;
|
||||
8
data/web/src/js/WebUI/Redux/actions/setWebSocket.js
Normal file
8
data/web/src/js/WebUI/Redux/actions/setWebSocket.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const SET_WEBSOCKET = 'SET_WEBSOCKET';
|
||||
|
||||
const setWebSocket = (webSocket) => ({
|
||||
type: SET_WEBSOCKET,
|
||||
webSocket,
|
||||
});
|
||||
|
||||
export default setWebSocket;
|
||||
25
data/web/src/js/WebUI/Redux/reducers/webUIReducer.js
Normal file
25
data/web/src/js/WebUI/Redux/reducers/webUIReducer.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import _assign from 'lodash-es/assign';
|
||||
|
||||
const initialState = {
|
||||
webSocket: null,
|
||||
availableDevices: [],
|
||||
};
|
||||
|
||||
const webUIReducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case 'SET_WEBSOCKET':
|
||||
return _assign({}, state, {
|
||||
webSocket: action.webSocket,
|
||||
});
|
||||
|
||||
case 'SET_AVAILABLE_DEVICES':
|
||||
return _assign({}, state, {
|
||||
availableDevices: action.devices,
|
||||
});
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default webUIReducer;
|
||||
97
data/web/src/js/WebUI/containers/WebUI.js
Normal file
97
data/web/src/js/WebUI/containers/WebUI.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import HeaderBar from '../../HeaderBar/components/HeaderBar';
|
||||
import Monitor from '../../Monitor/components/Monitor';
|
||||
import WidgetArea from '../../WidgetArea/containers/WidgetArea';
|
||||
import '../../../styles/WebUI/containers/WebUI.scss';
|
||||
|
||||
// Redux actions
|
||||
import setWebSocket from '../Redux/actions/setWebSocket';
|
||||
import WebSocketUtils from '../../global/WebSocketUtils';
|
||||
import updateGameState from '../../global/Redux/actions/updateGameState';
|
||||
|
||||
const mapReduxStateToProps = (reduxState) => ({
|
||||
connections: reduxState.gameState.connections,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
doSetWebSocket: (webSocket) => dispatch(setWebSocket(webSocket)),
|
||||
handleIncomingMessage: (message) => dispatch(WebSocketUtils.handleIncomingMessage(message)),
|
||||
doUpdateGameState: (gameState) => dispatch(updateGameState(gameState)),
|
||||
});
|
||||
|
||||
class WebUI extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.webSocket = null;
|
||||
this.webUiRef = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.webSocketConnect();
|
||||
}
|
||||
|
||||
webSocketConnect = () => {
|
||||
const getParams = new URLSearchParams(document.location.search.substring(1));
|
||||
const port = getParams.get('port');
|
||||
if (!port) { throw new Error('Unable to determine socket port from GET parameters'); }
|
||||
|
||||
const webSocketAddress = `ws://localhost:${port}`;
|
||||
try {
|
||||
this.props.webSocket.close();
|
||||
this.props.doSetWebSocket(null);
|
||||
} catch (error) {
|
||||
// Ignore errors caused by attempting to close an invalid WebSocket object
|
||||
}
|
||||
|
||||
const webSocket = new WebSocket(webSocketAddress);
|
||||
webSocket.onerror = () => {
|
||||
this.props.doUpdateGameState({
|
||||
connections: {
|
||||
snesDevice: this.props.connections.snesDevice,
|
||||
snesConnected: false,
|
||||
serverAddress: this.props.connections.serverAddress,
|
||||
serverConnected: false,
|
||||
},
|
||||
});
|
||||
setTimeout(this.webSocketConnect, 5000);
|
||||
};
|
||||
webSocket.onclose = () => {
|
||||
// If the WebSocket connection is closed for some reason, attempt to reconnect
|
||||
this.props.doUpdateGameState({
|
||||
connections: {
|
||||
snesDevice: this.props.connections.snesDevice,
|
||||
snesConnected: false,
|
||||
serverAddress: this.props.connections.serverAddress,
|
||||
serverConnected: false,
|
||||
},
|
||||
});
|
||||
setTimeout(this.webSocketConnect, 5000);
|
||||
};
|
||||
|
||||
// Dispatch a custom event when websocket messages are received
|
||||
webSocket.onmessage = (message) => {
|
||||
this.props.handleIncomingMessage(message);
|
||||
};
|
||||
|
||||
// Store the webSocket object in the Redux store so other components can access it
|
||||
webSocket.onopen = () => {
|
||||
this.props.doSetWebSocket(webSocket);
|
||||
webSocket.send(WebSocketUtils.formatSocketData('webStatus', 'connections'));
|
||||
};
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="web-ui" ref={ this.webUiRef }>
|
||||
<HeaderBar />
|
||||
<div id="content-middle">
|
||||
<Monitor />
|
||||
<WidgetArea />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapReduxStateToProps, mapDispatchToProps)(WebUI);
|
||||
Reference in New Issue
Block a user