From 543f70154205a96fa5f62597219056ed213074fd Mon Sep 17 00:00:00 2001 From: knoxfighter Date: Sat, 21 Jul 2018 16:53:53 +0200 Subject: [PATCH 01/53] updated everything (functiontests pending) --- .gitignore | 6 +- mix-manifest.json | 4 + package.json | 44 ++ ui/App/App.jsx | 61 ++- ui/App/components/Config/Settings.jsx | 5 +- ui/App/components/ConfigContent.jsx | 392 ++++++++++-------- ui/App/components/ConsoleContent.jsx | 30 +- ui/App/components/Header.jsx | 14 +- ui/App/components/HiddenSidebar.jsx | 15 +- ui/App/components/Index.jsx | 46 +- ui/App/components/LoginContent.jsx | 93 ++--- ui/App/components/Logs/LogLines.jsx | 5 +- ui/App/components/LogsContent.jsx | 4 +- ui/App/components/Mods/Mod.jsx | 21 +- ui/App/components/Mods/ModManager.jsx | 11 +- ui/App/components/Mods/ModOverview.jsx | 25 +- ui/App/components/Mods/ModUpload.jsx | 5 +- .../Mods/search/ModFoundOverview.jsx | 5 +- ui/App/components/Mods/search/ModSearch.jsx | 10 +- ui/App/components/ModsContent.jsx | 7 +- ui/App/components/Saves/CreateSave.jsx | 3 +- ui/App/components/Saves/Save.jsx | 9 +- ui/App/components/Saves/SavesList.jsx | 7 +- ui/App/components/Saves/UploadSave.jsx | 3 +- ui/App/components/SavesContent.jsx | 4 +- ui/App/components/ServerCtl/ServerCtl.jsx | 26 +- ui/App/components/ServerCtl/ServerStatus.jsx | 15 +- ui/App/components/Sidebar.jsx | 62 ++- ui/App/components/Users/AddUser.jsx | 47 ++- ui/App/components/Users/UserTable.jsx | 5 +- ui/App/components/UsersContent.jsx | 19 +- ui/index.js | 29 +- ui/package.json | 33 -- ui/socket.js | 16 +- ui/webpack.config.js | 19 - webpack.mix.js | 11 + 36 files changed, 624 insertions(+), 487 deletions(-) create mode 100644 mix-manifest.json create mode 100644 package.json delete mode 100644 ui/package.json delete mode 100644 ui/webpack.config.js create mode 100644 webpack.mix.js diff --git a/.gitignore b/.gitignore index 7f00102b..10667da0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ node_modules/ dev/ bundle.js -factorio-server-manager -factorio_server_manager +/factorio-server-manager* +/factorio_server_manager* auth.leveldb* conf.json *.exe @@ -10,6 +10,6 @@ build/ /mod_packs/* npm-debug.log .idea/ -/ui/package-lock.json +/package-lock.json factorio.auth /pkg/ diff --git a/mix-manifest.json b/mix-manifest.json new file mode 100644 index 00000000..33642fb9 --- /dev/null +++ b/mix-manifest.json @@ -0,0 +1,4 @@ +{ + "/app/bundle.js": "/app/bundle.js", + "/app/bundle.js.map": "/app/bundle.js.map" +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..ef13c1a4 --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "factorio-mod-manager", + "version": "0.2.0", + "description": "Factorio Server Manager UI", + "main": "ui/index.js", + "scripts": { + "dev": "npm run development", + "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch-poll": "npm run watch -- --watch-poll", + "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", + "build": "npm run production", + "prod": "npm run production", + "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/mroote/factorio-server-manager.git" + }, + "author": "Mitch Roote ", + "license": "MIT", + "bugs": { + "url": "https://github.com/mroote/factorio-server-manager/issues" + }, + "homepage": "https://github.com/mroote/factorio-server-manager#readme", + "devDependencies": { + "babel-core": "^6.26.3", + "babel-preset-react": "^6.24.1", + "cross-env": "^5.2.0", + "laravel-mix": "^2.1.11", + "locks": "^0.2.2", + "node-sass": "^4.9.2", + "react": "^16.4.1", + "react-console-component": "^0.6.1", + "react-dom": "^16.4.1", + "react-native-listener": "^1.0.2", + "react-router": "^4.3.1", + "react-router-dom": "^4.3.1", + "semver": "^5.5.0", + "sweetalert": "^2.1.0", + "prop-types": "latest" + } +} diff --git a/ui/App/App.jsx b/ui/App/App.jsx index 79844236..7b3542b0 100644 --- a/ui/App/App.jsx +++ b/ui/App/App.jsx @@ -1,10 +1,17 @@ import React from 'react'; -import {browserHistory} from 'react-router'; +import {Switch, Route} from 'react-router-dom'; import Header from './components/Header.jsx'; import Sidebar from './components/Sidebar.jsx'; import Footer from './components/Footer.jsx'; import HiddenSidebar from './components/HiddenSidebar.jsx'; import Socket from '../socket.js'; +import Index from "./components/Index"; +import UsersContent from "./components/UsersContent"; +import ModsContent from "./components/ModsContent"; +import LogsContent from "./components/LogsContent"; +import SavesContent from "./components/SavesContent"; +import ConfigContent from "./components/ConfigContent"; +import ConsoleContent from "./components/ConsoleContent"; class App extends React.Component { constructor(props) { @@ -94,10 +101,10 @@ class App extends React.Component { error: (xhr, status, err) => { console.log('api/saves/list', status, err.toString()); } - }) + }); if (!this.state.saves) { - this.setState({saves:[]}) + this.setState({saves:[]}); } } @@ -135,9 +142,23 @@ class App extends React.Component { // render main application, // if logged in show application // if not logged in show Not logged in message - var resp; + let appProps = { + message: "", + messages: this.state.messages, + flashMessage: this.flashMessage, + facServStatus: this.facServStatus, + serverStatus: this.state.serverStatus, + factorioVersion: this.state.factorioVersion, + getStatus: this.getStatus, + saves: this.state.saves, + getSaves: this.getSaves, + username: this.state.username, + socket: this.socket + }; + + let resp; if (this.state.loggedIn) { - var resp = + resp =
// Render react-router components and pass in props - {React.cloneElement( - this.props.children, - { - message: "", - messages: this.state.messages, - flashMessage: this.flashMessage, - facServStatus: this.facServStatus, - serverStatus: this.state.serverStatus, - factorioVersion: this.state.factorioVersion, - getStatus: this.getStatus, - saves: this.state.saves, - getSaves: this.getSaves, - username: this.state.username, - socket: this.socket - } - )} + + {return }}/> + {return }}/> + {return }}/> + {return }}/> + {return }}/> + {return }}/> + {return }}/> + {return }}/> +
@@ -178,12 +193,12 @@ class App extends React.Component { />
} else { - var resp =

Not Logged in

; + resp =

Not Logged in

; } return(
- {resp} + {resp}
) } diff --git a/ui/App/components/Config/Settings.jsx b/ui/App/components/Config/Settings.jsx index c84dd132..61b16121 100644 --- a/ui/App/components/Config/Settings.jsx +++ b/ui/App/components/Config/Settings.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; class Settings extends React.Component { constructor(props) { @@ -23,8 +24,8 @@ class Settings extends React.Component { } Settings.propTypes = { - section: React.PropTypes.string.isRequired, - config: React.PropTypes.object.isRequired, + section: PropTypes.string.isRequired, + config: PropTypes.object.isRequired, } export default Settings diff --git a/ui/App/components/ConfigContent.jsx b/ui/App/components/ConfigContent.jsx index 7346a118..8f142af1 100644 --- a/ui/App/components/ConfigContent.jsx +++ b/ui/App/components/ConfigContent.jsx @@ -1,13 +1,21 @@ import React from 'react'; -import {IndexLink} from 'react-router'; +import {Link} from 'react-router-dom'; import Settings from './Config/Settings.jsx'; //https://stackoverflow.com/a/1414175 -function stringToBoolean(string){ - switch(string.toLowerCase().trim()){ - case "true": case "yes": case "1": return true; - case "false": case "no": case "0": case null: return false; - default: return Boolean(string); +function stringToBoolean(string) { + switch(string.toLowerCase().trim()) { + case "true": + case "yes": + case "1": + return true; + case "false": + case "no": + case "0": + case null: + return false; + default: + return Boolean(string); } } @@ -39,24 +47,24 @@ class ConfigContent extends React.Component { let fieldValue var change = this.state.serverSettings; - if (e.target.value === "true" || e.target.value === "false") { - // Ensure Boolean type is used if required - if (e.target.id === "lan" || e.target.id === "public") { - if (e.target.value == "true") { - fieldValue = true - } else { - fieldValue = false + if(e.target.value === "true" || e.target.value === "false") { + // Ensure Boolean type is used if required + if(e.target.id === "lan" || e.target.id === "public") { + if(e.target.value == "true") { + fieldValue = true + } else { + fieldValue = false + } + change["visibility"][e.target.id] = fieldValue + this.setState({serverSettings: change}); + return; } - change["visibility"][e.target.id] = fieldValue - this.setState({serverSettings: change}); - return; - } - fieldValue = stringToBoolean(e.target.value) - } else if (e.target.id === "admins" || e.target.id === "tags") { - // Split settings values that are stored as arrays - fieldValue = e.target.value.split(",") + fieldValue = stringToBoolean(e.target.value) + } else if(e.target.id === "admins" || e.target.id === "tags") { + // Split settings values that are stored as arrays + fieldValue = e.target.value.split(",") } else { - fieldValue = e.target.value + fieldValue = e.target.value } console.log(name, fieldValue) change[name] = fieldValue; @@ -69,7 +77,7 @@ class ConfigContent extends React.Component { url: "/api/config", dataType: "json", success: (resp) => { - if (resp.success === true) { + if(resp.success === true) { this.setState({config: resp.data}) } }, @@ -84,7 +92,7 @@ class ConfigContent extends React.Component { url: "/api/settings", dataType: "json", success: (resp) => { - if (resp.success === true) { + if(resp.success === true) { this.setState({serverSettings: resp.data}) console.log(this.state) } @@ -105,7 +113,7 @@ class ConfigContent extends React.Component { data: serverSettingsJSON, success: (data) => { console.log(data); - if (data.success === true) { + if(data.success === true) { console.log("settings updated") } } @@ -113,123 +121,130 @@ class ConfigContent extends React.Component { } formTypeField(key, setting) { - if (key.startsWith("_comment_")) { + if(key.startsWith("_comment_")) { return ( ) } switch(typeof setting) { - case "number": - return ( - - ) - case "string": - if (key.includes("password")) { - return ( - - ) - } else { - return ( - - ) - } - case "boolean": - return ( - - ) - case "object": - if (Array.isArray(setting)) { - return ( - - ) - } else { - if (key.includes("visibility")) { - let vis_fields = [] - for (const key in setting) { - const field = -
-

{key}

- -
- vis_fields.push(field) + case "number": + return ( + + ) + case "string": + if(key.includes("password")) { + return ( + + ) + } else { + return ( + + ) } + case "boolean": + return ( + + ) + case "object": + if(Array.isArray(setting)) { + return ( + + ) + } else { + if(key.includes("visibility")) { + let vis_fields = [] + for(const key in setting) { + const field = +
+

{key}

+ +
+ vis_fields.push(field) + } - return vis_fields - } - } - default: - return ( - - ) + return vis_fields + } + } + default: + return ( + + ) } } render() { - return( + return (
-

- Config - Manage game configuration -

-
    -
  1. Server Control
  2. -
  3. Here
  4. -
+

+ Config + Manage game configuration +

+
    +
  1. Server Control
  2. +
  3. Here
  4. +
@@ -239,38 +254,57 @@ class ConfigContent extends React.Component {
-
-
-
-
-
- {Object.keys(this.state.serverSettings).map(function(key) { - if (key.startsWith("_comment_")) - return(
{this.formTypeField(key, setting)}
); - var setting = this.state.serverSettings[key] - var setting_key = this.capitalizeFirstLetter(key.replace(/_/g, " ")) - var comment = this.state.serverSettings["_comment_" + key] - return( -
- -
- {this.formTypeField(key, setting)} -

{comment}

-
-
- ) - }, this)} -
-
- +
+
+
+
+ + { + Object.keys(this.state.serverSettings).map(function(key) { + if(key.startsWith("_comment_")) { + return ( +
+ {this.formTypeField(key, setting)} +
+ ); + } + + var setting = this.state.serverSettings[key] + var setting_key = this.capitalizeFirstLetter(key.replace(/_/g, " ")) + var comment = this.state.serverSettings["_comment_" + key] + + return ( +
+ +
+ { + this.formTypeField(key, setting) + } +

{comment}

+
+
+ ) + }, this) + } +
+
+ +
-
- + +
-
@@ -281,37 +315,35 @@ class ConfigContent extends React.Component {
-
-
- {Object.keys(this.state.config).map(function(key) { - var conf = this.state.config[key] - return( -
-

{key}

-
- - - - - - - - -
Setting nameSetting value
-
-
- ) - }, this)} +
+
+ {Object.keys(this.state.config).map(function(key) { + var conf = this.state.config[key] + return ( +
+

{key}

+
+ + + + + + + + +
Setting nameSetting value
+
+
+ ) + }, this)} +
-
- -
) } diff --git a/ui/App/components/ConsoleContent.jsx b/ui/App/components/ConsoleContent.jsx index eca086b7..3dacd712 100644 --- a/ui/App/components/ConsoleContent.jsx +++ b/ui/App/components/ConsoleContent.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import {IndexLink} from 'react-router'; +import {Link} from 'react-router-dom'; +import PropTypes from 'prop-types'; class ConsoleContent extends React.Component { constructor(props) { @@ -11,6 +12,8 @@ class ConsoleContent extends React.Component { this.addHistory = this.addHistory.bind(this); this.handleClick = this.handleClick.bind(this); this.newLogLine = this.newLogLine.bind(this); + this.subscribeLogToSocket = this.subscribeLogToSocket.bind(this); + this.state = { commands: {}, history: [], @@ -19,16 +22,27 @@ class ConsoleContent extends React.Component { } componentDidMount() { - this.props.socket.emit("log subscribe"); + this.subscribeLogToSocket(); + } + + subscribeLogToSocket() { + let wsReadyState = this.props.socket.emit("log subscribe"); + if(wsReadyState != WebSocket.OPEN) { + setTimeout(() => { + this.subscribeLogToSocket(); + }, 50); + + return; + } this.setState({connected: true}); - + this.props.socket.on('log update', this.newLogLine.bind(this)); } componentDidUpdate() { - var el = this.refs.output; - var container = document.getElementById("console-output"); - container.scrollTop = this.refs.output.scrollHeight; + var el = this.refs.output; + var container = document.getElementById("console-output"); + container.scrollTop = this.refs.output.scrollHeight; } handleInput(e) { @@ -82,7 +96,7 @@ class ConsoleContent extends React.Component { Send commands and messages to the Factorio server
    -
  1. Server Control
  2. +
  3. Server Control
  4. Here
@@ -105,7 +119,7 @@ class ConsoleContent extends React.Component { } ConsoleContent.propTypes = { - socket: React.PropTypes.object.isRequired, + socket: PropTypes.object.isRequired, } export default ConsoleContent; diff --git a/ui/App/components/Header.jsx b/ui/App/components/Header.jsx index e66675db..88f17762 100644 --- a/ui/App/components/Header.jsx +++ b/ui/App/components/Header.jsx @@ -1,5 +1,6 @@ import React from 'react'; -import {Link, IndexLink, browserHistory} from 'react-router'; +import {Link, withRouter} from 'react-router-dom'; +import PropTypes from 'prop-types'; class Header extends React.Component { constructor(props) { @@ -16,9 +17,10 @@ class Header extends React.Component { console.log(resp) } }); + // Wait for 1 second for logout callback to complete setTimeout(() => { - browserHistory.push("/login"); + this.props.history.push("/login") }, 1000); } @@ -38,7 +40,7 @@ class Header extends React.Component { return(
- FactorioSM + FactorioSM