diff --git a/app/components/ConsoleView/ConsoleView.js b/app/components/ConsoleView/ConsoleView.js
index e45eacb8..4f3c8e14 100644
--- a/app/components/ConsoleView/ConsoleView.js
+++ b/app/components/ConsoleView/ConsoleView.js
@@ -8,7 +8,7 @@ import {sendCommandToServer} from '../../utils/sendCommandToServer';
import {log} from '../../utils/loggerUtils';
const welcomeMessage = `MisRCON-by @Csprance
-v0.0.1 - Babycakes
+v0.0.2 - Macadocious
Type help for more options.
--------------------------
diff --git a/app/components/InfoView/InfoView.js b/app/components/InfoView/InfoView.js
index b8c1f4c7..25e39643 100644
--- a/app/components/InfoView/InfoView.js
+++ b/app/components/InfoView/InfoView.js
@@ -11,7 +11,7 @@ export default class InfoView extends Component {
render() {
return (
- TODO: Bans TAB
+ TODO: INFO TAB
);
}
diff --git a/app/components/PlayersView/PlayerCard.js b/app/components/PlayersView/PlayerCard.js
new file mode 100644
index 00000000..fa294070
--- /dev/null
+++ b/app/components/PlayersView/PlayerCard.js
@@ -0,0 +1,97 @@
+/**
+ * Name: PlayersCard
+ * Author: Chrissprance
+ * Creation Date: 12/9/2016
+ * Description: Component used to display player information from the server as well as from the localStorage
+ */
+import React, {
+ Component,
+ PropTypes,
+} from 'react';
+import styled from 'styled-components';
+import {Card, CardActions, CardHeader, CardTitle, CardText} from 'material-ui/Card';
+import FlatButton from 'material-ui/FlatButton';
+import TextField from 'material-ui/TextField';
+import store from 'store';
+import axios from 'axios';
+
+import Spacer from '../common/Spacer';
+import {darkGrey, white} from '../../styles/colors';
+import {log} from '../../utils/loggerUtils';
+import ExternalLink from '../common/ExternalLink'
+
+
+class PlayersCard extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ avatar: 'http://placehold.it/42x42',
+ notes: store.get(this.props.steam) !== undefined ? store.get(this.props.steam).notes : ''
+ }
+ }
+
+ componentWillMount() {
+ this.getAvatar();
+ }
+
+ getAvatar = () => {
+ axios.get('https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/', {
+ params: {
+ key: 'C4E62F89FF5D569A481850BCD3098D52',
+ steamids: this.props.steam
+ }
+ }).then((res) => {
+ this.setState({
+ avatar: res.data.response.players[0].avatar,
+ });
+ }).catch((err) => {
+ log('error', err);
+ });
+ };
+
+ updateNotes = (e) => {
+ this.setState({
+ notes: e.target.value,
+ });
+ store.set(this.props.steam, {avatar: this.state.avatar, notes: e.target.value});
+ };
+
+ render() {
+ const link = String('https://steamrep.com/profiles/' + this.props.steam);
+ return (
+
+
+ {this.props.steam}}
+ />
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+PlayersCard.propTypes = {};
+PlayersCard.defaultProps = {};
+
+const PCard = styled.div`
+ flex-basis: 20%;
+ margin: 5px;
+`;
+
+
+export default PlayersCard;
diff --git a/app/components/PlayersView/PlayersView.js b/app/components/PlayersView/PlayersView.js
index cc8492da..d47f8069 100644
--- a/app/components/PlayersView/PlayersView.js
+++ b/app/components/PlayersView/PlayersView.js
@@ -2,17 +2,148 @@
* Name: PlayersView
* Author: Chrissprance
* Creation Date: 12/8/2016
- * Description:
+ * Description: Contains the list of all the players currently on the server
*/
import React, {Component} from 'react';
+import styled, {keyframes} from 'styled-components';
+import store from 'store';
+import TextField from 'material-ui/TextField';
+import FloatingActionButton from 'material-ui/FloatingActionButton';
+import RefreshIcon from 'material-ui/svg-icons/navigation/refresh';
+import fuzzy from 'fuzzy';
+
+import Spacer from '../common/Spacer';
+import {JSONifyStatus} from '../../utils/JSONifyStatus';
+import {sendCommandToServer} from '../../utils/sendCommandToServer';
+import {log} from '../../utils/loggerUtils';
+import {white} from '../../styles/colors';
+import PlayerCard from './PlayerCard';
+
export default class PlayersView extends Component {
+ constructor(props, context) {
+ super(props, context);
+ this.state = {
+ loading: false,
+ credentials: store.get('userCredentials'),
+ players: [],
+ searchString: ''
+ };
+ }
+
+ componentWillMount() {
+ // Go and grab the player list from the server.
+ this.getPlayersAndAddToState();
+ }
+
+ getPlayersAndAddToState = () => {
+ this.setState({
+ loading: true,
+ });
+
+ sendCommandToServer('status', this.state.credentials)
+ .then((res) => {
+ if (res !== null) {
+ this.setState({
+ players: JSONifyStatus(res).players,
+ loading: false,
+ });
+ }
+ })
+ .catch((err) => {
+ log('error', err);
+ });
+ };
+
+
+ updateSearchString = (e) => {
+ this.setState({
+ searchString: e.target.value
+ });
+ };
+
+
render() {
+ const options = {
+ extract: (el) => {
+ return el.name
+ }
+ };
+ const fuzzyList = fuzzy.filter(this.state.searchString, this.state.players, options).map((el) => {
+ return el.string;
+ });
+ const filterList = this.state.players.filter((player) => {
+ return fuzzyList.indexOf(player.name) >= 0
+ });
return (
-
- TODO: Bans TAB
-
+
+
+
+
+
+
+ { (this.state.loading === true ? : ) }
+
+
+
+
+ {filterList.map((player) => {
+ return (
+
+ )
+ })}
+
+
);
}
}
+
+
+const rotate360 = keyframes`
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(360deg);
+ }
+`;
+
+const AnimatedRefresh = styled(RefreshIcon)`
+ display: inline-block;
+ animation: ${rotate360} 2s linear infinite;
+`;
+const Container = styled.div`
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+`;
+
+const SearchBar = styled(TextField)`
+ width: 40%;
+`;
+
+const Actions = styled.div`
+ height: 100px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding-bottom: 25px;
+ flex-shrink: 1;
+`;
+
+
+const PlayerList= styled.div`
+ width: 100%;
+ display: flex;
+ flex-flow: row wrap;
+ padding: 10px;
+ overflow-y: auto;
+ align-items: flex-start;
+ justify-content: center;
+`;
+
+
diff --git a/app/components/common/ExternalLink.js b/app/components/common/ExternalLink.js
new file mode 100644
index 00000000..848eea4a
--- /dev/null
+++ b/app/components/common/ExternalLink.js
@@ -0,0 +1,33 @@
+/**
+ * Name: ExternalLink
+ * Author: Chrissprance
+ * Creation Date: 12/9/2016
+ * Description: Handles sending a user to an external browser link
+ */
+import {log} from '../../utils/loggerUtils';
+import React, {
+ PropTypes,
+} from 'react';
+import styled from 'styled-components';
+
+const ExternalLink = (props) => {
+ const handleClick = () => {
+ require('electron').shell.openExternal(props.to);
+ log(`Navigating to External Link: ${props.to}`);
+ };
+
+ return (
+
+ {props.children}
+
+ );
+};
+
+ExternalLink.propTypes = {
+ to: PropTypes.string.isRequired
+};
+
+const Pointer = styled.div`
+ cursor: pointer;
+`;
+export default ExternalLink;
diff --git a/app/components/common/Spacer.js b/app/components/common/Spacer.js
new file mode 100644
index 00000000..f5d43799
--- /dev/null
+++ b/app/components/common/Spacer.js
@@ -0,0 +1,28 @@
+/**
+ * Name: Spacer
+ * Author: Chrissprance
+ * Creation Date: 12/9/2016
+ * Description: Spacer Component
+ */
+import React, {
+ PropTypes,
+} from 'react';
+import styled from 'styled-components';
+
+const Spacer = (props) => {
+ return (
+
+
+
+ );
+};
+
+
+Spacer.propTypes = {};
+Spacer.defaultProps = {};
+const SpacerDiv = styled.div`
+ flex-grow: 1;
+`;
+
+export default Spacer;
+
diff --git a/app/containers/HomePage.js b/app/containers/HomePage.js
index 0e530cec..e8c0d3d7 100644
--- a/app/containers/HomePage.js
+++ b/app/containers/HomePage.js
@@ -1,3 +1,5 @@
+// Handle the login
+
import React, {Component} from 'react';
import store from 'store';
@@ -30,6 +32,7 @@ export default class HomePage extends Component {
//noinspection JSMethodCanBeStatic
getStoredCredentials() {
+ // returns false if there are no stored credentials
return store.get('userCredentials') !== undefined;
}
diff --git a/app/package.json b/app/package.json
index b826ac8f..f1a48e99 100644
--- a/app/package.json
+++ b/app/package.json
@@ -1,7 +1,7 @@
{
"name": "MisRCON",
"productName": "MisRCON",
- "version": "0.0.1",
+ "version": "0.0.2",
"description": "RCON Tool for Miscreated game.",
"main": "./main.js",
"author": {
diff --git a/app/utils/JSONifyStatus.js b/app/utils/JSONifyStatus.js
new file mode 100644
index 00000000..b656a362
--- /dev/null
+++ b/app/utils/JSONifyStatus.js
@@ -0,0 +1,89 @@
+/**
+ * Name: JSONifyStatus
+ * Author: Chrissprance
+ * Creation Date: 12/9/2016
+ * Description: takes a string of a status command and JSONifys it.
+ */
+
+
+function getServerStatus(str) {
+ const regex = /-*[\s\S]*- */g;
+ return regex.exec(str)[0];
+}
+
+
+function getStatusObjectFromString(str) {
+ const serverNameRE = new RegExp('name: (.*)\r');
+ const ipRE = new RegExp('ip: (.*)\r');
+ const versionRE = new RegExp('version: (.*)\r');
+ const levelRE = new RegExp('level: (.*)\r');
+ const gamerulesRE = new RegExp('gamerules: (.*)\r');
+ const playersRE = new RegExp('players: (.*)\r');
+
+ return {
+ name: serverNameRE.exec(str) !== null ? serverNameRE.exec(str)[1] : '',
+ ip: ipRE.exec(str) !== null ? ipRE.exec(str)[1] : '',
+ version: versionRE.exec(str) !== null ? versionRE.exec(str)[1] : '',
+ level: levelRE.exec(str) !== null ? levelRE.exec(str)[1] : '',
+ gameRules: gamerulesRE.exec(str) !== null ? gamerulesRE.exec(str)[1] : '',
+ players: playersRE.exec(str) !== null ? playersRE.exec(str)[1] : ''
+ };
+
+}
+
+
+function getPlayersString(str) {
+ let pString = /Connection Status:[\s\S]*.*/g;
+ let newStr = pString.exec(String(str));
+ return newStr[0].replace('Connection Status:\r', '');
+}
+
+
+function splitPlayerStringRowsIntoArray(str) {
+ let stringArray = str.split('\r');
+ let playersArray = [];
+
+ const steamIdRE = new RegExp('steam: (.*) name:');
+ const nameRE = new RegExp('name: (.*) entID:');
+ const entIDRE = new RegExp('entID:(.*) id:');
+ const idRE = new RegExp('id:(.*) ip:');
+ const ipRE = new RegExp('ip:(.*) ping:');
+ const pingRE = new RegExp('ping:(.*) state:');
+ const stateRE = new RegExp('state:(.*) profile:');
+ const profileRE = new RegExp('profile: (.*)');
+
+ stringArray.forEach((player) => {
+ playersArray.push({
+ steam: steamIdRE.exec(player) !== null ? steamIdRE.exec(player)[1] : '',
+ name: nameRE.exec(player) !== null ? nameRE.exec(player)[1] : '',
+ entID: entIDRE.exec(player) !== null ? entIDRE.exec(player)[1] : '',
+ id: idRE.exec(player) !== null ? idRE.exec(player)[1] : '',
+ ip: ipRE.exec(player) !== null ? ipRE.exec(player)[1] : '',
+ ping: pingRE.exec(player) !== null ? pingRE.exec(player)[1] : '',
+ state: stateRE.exec(player) !== null ? stateRE.exec(player)[1] : '',
+ profile: profileRE.exec(player) !== null ? profileRE.exec(player)[1] : '',
+ });
+ });
+
+ return playersArray.filter((player) => {
+ return player.steam !== ''
+ })
+}
+
+
+export function JSONifyStatus(statusString) {
+ let serverStatusString = getServerStatus(statusString);
+ let serverStatusObject = getStatusObjectFromString(serverStatusString);
+
+ let playersString = getPlayersString(statusString);
+ let playersArray = splitPlayerStringRowsIntoArray(playersString);
+
+
+ return {
+ serverStatus: {
+ serverStatusObject
+ },
+ players: playersArray
+ }
+}
+
diff --git a/app/utils/loggerUtils.js b/app/utils/loggerUtils.js
index 3bddd17e..a89a3d51 100644
--- a/app/utils/loggerUtils.js
+++ b/app/utils/loggerUtils.js
@@ -12,9 +12,9 @@ import format from 'date-fns/format';
/**
* Replaces the time of a date [time, date]
* @param: {string} lvl the log level to log at [silly, debug, info, warn, error] defaults to info
- * @param: {msg} msg the msg or object to log out
+ * @param: {msg} msg the msg or object to log out
*/
-export function log(lvl='info', msg) {
+export function log(lvl = 'info', msg) {
let logPath = 'misrcon.log';
let logMsg = `[${lvl}] - ${format(Date.now(), 'MM/DD/YY @ HH:mm:ss')} - ${msg}\n`;
// some things we don't want to log to a file what are they?
@@ -29,7 +29,7 @@ export function log(lvl='info', msg) {
} else {
// if it's not in the ignore file log list then log it to a file
fs.appendFile(logPath, logMsg, (err) => {
- console.log(err);
+ if (err) console.log(err);
});
}
}
diff --git a/package.json b/package.json
index 12367e08..49de033e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "MisRCON",
"productName": "MisRCON",
- "version": "0.0.1",
+ "version": "0.0.2",
"description": "RCON Tool for Miscreated game.",
"main": "main.js",
"scripts": {
@@ -161,6 +161,7 @@
"date-fns": "^1.11.2",
"electron-debug": "^1.1.0",
"font-awesome": "^4.7.0",
+ "fuzzy": "^0.1.3",
"jquery": "^3.1.1",
"json2xml": "^0.1.3",
"later": "^1.2.0",
diff --git a/webpack.config.development.js b/webpack.config.development.js
index 5e56df9c..6e30cbfa 100644
--- a/webpack.config.development.js
+++ b/webpack.config.development.js
@@ -3,7 +3,7 @@
* Build config for development process that uses Hot-Module-Replacement
* https://webpack.github.io/docs/hot-module-replacement-with-webpack.html
*/
-
+import path from 'path';
import webpack from 'webpack';
import validate from 'webpack-validator';
import merge from 'webpack-merge';