diff --git a/backend/blueprints/spa_api/service_layers/homepage/recent.py b/backend/blueprints/spa_api/service_layers/homepage/recent.py index 8c7d71388..dd689e466 100644 --- a/backend/blueprints/spa_api/service_layers/homepage/recent.py +++ b/backend/blueprints/spa_api/service_layers/homepage/recent.py @@ -1,8 +1,11 @@ +import json + from sqlalchemy import desc from backend.blueprints.spa_api.service_layers.replay.replay import CompactReplay from backend.blueprints.spa_api.service_layers.utils import with_session from backend.database.objects import Game +from backend.database.startup import lazy_get_redis class RecentReplays: @@ -17,8 +20,14 @@ def create(cls): @staticmethod @with_session def get_recent_replays(session=None): - replays = session.query(Game).order_by(desc(Game.upload_date))[:5][::-1] - return [CompactReplay.create_from_game(r).__dict__ for r in replays] + r = lazy_get_redis() + if r is not None and r.get('recent_replays') is not None: + return json.loads(r.get('recent_replays')) + replays = session.query(Game).order_by(desc(Game.upload_date))[:5] + replays = [CompactReplay.create_from_game(r).__dict__ for r in replays] + if r is not None: + r.set('recent_replays', json.dumps(replays), ex=60 * 60) + return replays if __name__ == '__main__': diff --git a/backend/blueprints/spa_api/service_layers/ml/ml.py b/backend/blueprints/spa_api/service_layers/ml/ml.py index 554d47271..07caae416 100644 --- a/backend/blueprints/spa_api/service_layers/ml/ml.py +++ b/backend/blueprints/spa_api/service_layers/ml/ml.py @@ -1,12 +1,13 @@ import glob import os +import numpy as np +import pandas as pd import torch import torch.nn as nn -import pandas as pd +from sqlalchemy import inspect from backend.database.objects import PlayerGame -from sqlalchemy import inspect def object_as_dict(obj): @@ -40,18 +41,25 @@ class RankPredictor: # MODEL_DIR = os.path.abspath(os.path.join('..', '..', '..', '..', '..', 'data', 'models')) MODEL_DIR = os.path.abspath(os.path.join('data', 'models')) models = {} - maxs = None - mins = None + maxs = {} + mins = {} def __init__(self): - # Load models - for model in sorted(glob.glob(os.path.join(self.MODEL_DIR, '*.mdl'))): - state = torch.load(model, map_location='cpu') - m = RankPredictorEnsemble() - m.load_state_dict(state) - self.models[os.path.basename(model).split('.')[0]] = m - self.maxs = pd.read_csv(os.path.join(self.MODEL_DIR, 'maxs.csv'), index_col=0, squeeze=True, header=None) - self.mins = pd.read_csv(os.path.join(self.MODEL_DIR, 'mins.csv'), index_col=0, squeeze=True, header=None) + possible_playlists = [playlist for playlist in os.listdir(self.MODEL_DIR) if + os.path.isdir(os.path.join(self.MODEL_DIR, playlist))] + for playlist_dir in possible_playlists: + self.models[playlist_dir] = {} + playlist_loc = os.path.join(self.MODEL_DIR, playlist_dir) + # Load models + for model in sorted(glob.glob(os.path.join(playlist_loc, '*.mdl'))): + state = torch.load(model, map_location='cpu') + m = RankPredictorEnsemble() + m.load_state_dict(state) + self.models[playlist_dir][os.path.basename(model).split('.')[0]] = m + self.maxs[playlist_dir] = pd.read_csv(os.path.join(playlist_loc, 'maxs.csv'), index_col=0, squeeze=True, + header=None) + self.mins[playlist_dir] = pd.read_csv(os.path.join(playlist_loc, 'mins.csv'), index_col=0, squeeze=True, + header=None) @staticmethod def process_input_data(input_, maxs, mins): @@ -73,31 +81,37 @@ def process_input_data(input_, maxs, mins): # mins = input.min() # maxs = input.max() input = (input - mins) / (maxs - mins) + input = input.fillna(0.0) + input = input.replace([np.inf, -np.inf], 0.0) output = nonzero['rank'] return input, output, maxs, mins - def convert_sql_object_to_numpy(self, obj: PlayerGame): + def convert_sql_object_to_numpy(self, obj: PlayerGame, playlist: int): + playlist = str(playlist) obj = object_as_dict(obj) a = pd.Series(obj) - input, _, __, ___ = self.process_input_data(a, self.maxs, self.mins) + input, _, __, ___ = self.process_input_data(a, self.maxs[playlist], self.mins[playlist]) obj = input.values return obj - def predict_rank(self, x: PlayerGame) -> int: - x = self.convert_sql_object_to_numpy(x) + def predict_rank(self, x: PlayerGame, playlist: int) -> int: + print(playlist) + x = self.convert_sql_object_to_numpy(x, playlist) result = pd.DataFrame(index=list(range(len(x)))) - for rank, m in self.models.items(): + if str(playlist) not in self.models: + return None + models = self.models[str(playlist)] + for rank, m in models.items(): result = result.merge( pd.Series(100 * m(x.astype(float)).detach().cpu().numpy(), name=str(rank)).to_frame(), left_index=True, right_index=True) - # print(result) + print(result) result = (result > 50).apply(lambda x: int(x.idxmin()), axis=1).values return int(result[0]) model_holder = RankPredictor() - if __name__ == '__main__': from backend.database.startup import lazy_startup diff --git a/backend/blueprints/spa_api/service_layers/player/player_profile_stats.py b/backend/blueprints/spa_api/service_layers/player/player_profile_stats.py index 03a731aaa..b6a0fb0ee 100644 --- a/backend/blueprints/spa_api/service_layers/player/player_profile_stats.py +++ b/backend/blueprints/spa_api/service_layers/player/player_profile_stats.py @@ -1,14 +1,14 @@ from typing import List -from sqlalchemy import func, desc, cast, String, literal_column +from sqlalchemy import func, desc, cast, String from sqlalchemy.dialects import postgresql from backend.blueprints.spa_api.service_layers.replay.replay_player import Loadout from backend.blueprints.spa_api.service_layers.utils import with_session +from backend.data.constants.car import get_car from backend.database.objects import PlayerGame, Game, Player from backend.database.wrapper.player_wrapper import PlayerWrapper from backend.database.wrapper.stats.player_stat_wrapper import PlayerStatWrapper -from backend.data.constants.car import get_car player_wrapper = PlayerWrapper(limit=10) player_stat_wrapper = PlayerStatWrapper(player_wrapper) @@ -48,15 +48,13 @@ def _get_most_played_with(id_: str, session): result = session.query(p, func.count(Game.players).label('count')).filter( Game.players.contains(cast([id_], - postgresql.ARRAY(String)))).group_by('player').order_by(desc('count')).subquery( - 't') - result = session.query(result, Player.platformname).join(Player, - Player.platformid == result.c.player).filter( - Player.platformid != id_).filter(literal_column('count') > 1)[:3] + postgresql.ARRAY(String)))).group_by('player').order_by(desc('count')) + result = result[1:4] for p in result: player = session.query(Player).filter(Player.platformid == p[0]).first() if player is None or player.platformname == "": - players_in_common.append(PlayerInCommonStats(name=p[2], count=p[1], id=p[0], avatar=player.avatar)) + print("unknown player") + players_in_common.append(PlayerInCommonStats(name="Unknown", count=p[1], id=p[0], avatar=player.avatar)) else: players_in_common.append( PlayerInCommonStats(name=player.platformname, count=p[1], id=p[0], avatar=player.avatar)) @@ -86,7 +84,6 @@ def _get_favourite_car(id_: str, session): def _get_most_recent_loadout(id_: str, session): pg = session.query(PlayerGame) \ .join(Game, PlayerGame.game == Game.hash) \ - .distinct(PlayerGame.player) \ .filter(PlayerGame.player == id_) \ .order_by(desc(PlayerGame.player), desc(Game.match_date)) \ .first() diff --git a/backend/blueprints/spa_api/service_layers/replay/predicted_ranks.py b/backend/blueprints/spa_api/service_layers/replay/predicted_ranks.py index fbf0962ec..81e84ec61 100644 --- a/backend/blueprints/spa_api/service_layers/replay/predicted_ranks.py +++ b/backend/blueprints/spa_api/service_layers/replay/predicted_ranks.py @@ -9,7 +9,8 @@ from backend.blueprints.spa_api.service_layers.ml.ml import model_holder except ModuleNotFoundError: model_holder = None - print("Not using ML because required packages are not installed. Run `pip install -r requirements-ml.txt` to use ML.") + print( + "Not using ML because required packages are not installed. Run `pip install -r requirements-ml.txt` to use ML.") class PredictedRank: @@ -31,15 +32,40 @@ def create_from_id(id_: str, session=None) -> List['PredictedRank']: game: Game = session.query(Game).filter(Game.hash == id_).first() accepted_playlists = [ - 13, # standard + 1, # unranked duels + 2, # unranked doubles 3, # unranked standard - 6, # custom + 6, # custom, + 10, # ranked duels + 11, # doubles + 13, # standard + 27, # hoops + 28, # rumble + 29, # dropshot + 30, # snow day ] if game.playlist not in accepted_playlists: raise UnsupportedPlaylist playergames = session.query(PlayerGame).filter(PlayerGame.game == id_).all() - + adjusted_playlist_map = { + 1: 10, + 10: 10, + 2: 11, + 11: 11, + 3: 13, + 6: 13, + 13: 13, + 27: 27, + 28: 28, + 29: 29, + 30: 30 + } + playlist = adjusted_playlist_map[game.playlist] + if game.playlist == 6 and len(game.players) == 4: + playlist = 11 + elif game.playlist == 6 and len(game.players) == 2: + playlist = 10 if is_local_dev(): import random ranks = [ @@ -48,7 +74,7 @@ def create_from_id(id_: str, session=None) -> List['PredictedRank']: ] else: ranks = [ - PredictedRank(pg.player, model_holder.predict_rank(pg)) + PredictedRank(pg.player, model_holder.predict_rank(pg, playlist=playlist)) for pg in playergames ] return ranks diff --git a/backend/blueprints/spa_api/service_layers/replay/replay.py b/backend/blueprints/spa_api/service_layers/replay/replay.py index 711e10940..c6415cb8c 100644 --- a/backend/blueprints/spa_api/service_layers/replay/replay.py +++ b/backend/blueprints/spa_api/service_layers/replay/replay.py @@ -1,11 +1,11 @@ -from typing import List, cast +from typing import List, cast, Dict from backend.blueprints.spa_api.errors.errors import ReplayNotFound, Redirect from backend.blueprints.spa_api.service_layers.replay.json_tag import JsonTag from backend.blueprints.spa_api.service_layers.replay.replay_player import ReplayPlayer from backend.blueprints.spa_api.service_layers.utils import sort_player_games_by_team_then_id, with_session from backend.data.constants.playlist import get_playlist -from backend.database.objects import Game, PlayerGame, GameVisibilitySetting +from backend.database.objects import Game, PlayerGame, GameVisibilitySetting, Player from backend.utils.safe_flask_globals import get_current_user_id @@ -23,7 +23,7 @@ class Replay: def __init__(self, id_: str, name: str, date: str, map: str, game_mode: str, game_score: GameScore, players: List[ReplayPlayer], tags: List[JsonTag], visibility: GameVisibilitySetting, - ranks: List[int], mmrs: List[int]): + ranks: List[int], mmrs: List[int], group_map: Dict[str, List[int]]): self.id = id_ self.name = name self.date = date @@ -35,6 +35,7 @@ def __init__(self, id_: str, name: str, date: str, map: str, self.visibility = visibility.value self.ranks = ranks self.mmrs = mmrs + self.groupMap = group_map @staticmethod @with_session @@ -45,11 +46,15 @@ def create_from_id(id_: str, session=None) -> 'Replay': if game is None: raise ReplayNotFound() raise Redirect("/replays/" + game.hash) - replay = Replay.create_from_game(game) + replay = Replay.create_from_game(game, session=session, groups=True) return replay @staticmethod - def create_from_game(game: Game, full=True) -> 'Replay': + def create_from_game(game: Game, full=True, groups=False, session=None) -> 'Replay': + group_map = None + if groups and session is not None: + players = session.query(Player).filter(Player.platformid.in_(game.players)).all() + group_map = {player.platformid: player.groups for player in players} return Replay( id_=game.hash, name=game.name, @@ -68,8 +73,8 @@ def create_from_game(game: Game, full=True) -> 'Replay': ], visibility=game.visibility, ranks=game.ranks, - mmrs=game.mmrs - + mmrs=game.mmrs, + group_map=group_map ) diff --git a/backend/blueprints/spa_api/spa_api.py b/backend/blueprints/spa_api/spa_api.py index c64e20795..df43dc313 100644 --- a/backend/blueprints/spa_api/spa_api.py +++ b/backend/blueprints/spa_api/spa_api.py @@ -131,7 +131,12 @@ def encode_bot_name(w): @bp.route('/global/replay_count') @with_session def api_get_replay_count(session=None): + r = lazy_get_redis() + if r is not None and r.get('replay_count') is not None: + return jsonify(int(r.get('replay_count'))) count = session.query(Game.hash).count() + if r is not None: + r.set('replay_count', str(count), ex=60 * 60) return jsonify(count) diff --git a/backend/database/objects.py b/backend/database/objects.py index ad12b3a6a..1b727b552 100644 --- a/backend/database/objects.py +++ b/backend/database/objects.py @@ -315,7 +315,7 @@ def validate_code(self, key, value): class Player(DBObjectBase): __tablename__ = 'players' - platformid = Column(String(40), primary_key=True) + platformid = Column(String(40), primary_key=True, unique=True) platformname = Column(String(50)) avatar = Column(String(150)) ranks = Column(postgresql.ARRAY(Integer, dimensions=1)) # foreign key diff --git a/backend/database/startup.py b/backend/database/startup.py index 8481ac7c7..2a8310ded 100644 --- a/backend/database/startup.py +++ b/backend/database/startup.py @@ -10,12 +10,22 @@ from backend.database.objects import DBObjectBase +try: + import config + DB_IP = config.DB_IP + DB_USER = config.DB_USER + DB_PASSWORD = config.DB_PASSWORD +except: + DB_IP = None + DB_USER = None + DB_PASSWORD = None + logger = logging.getLogger(__name__) def login(connection_string, recreate_database=False) -> Tuple[create_engine, sessionmaker]: print(connection_string) - engine = create_engine(connection_string, echo=False) + engine = create_engine(connection_string, echo=False, pool_recycle=1800) if recreate_database: conn = engine.connect() conn.execute("commit") @@ -32,20 +42,6 @@ def login(connection_string, recreate_database=False) -> Tuple[create_engine, se return engine, session -def startup() -> sessionmaker: - try: - # Sql Stuff - connection_string = 'postgresql:///saltie' - engine, session = login(connection_string) - except OperationalError as e: - print('trying backup info', e) - try: - engine, session = login('postgresql://postgres:postgres@localhost/saltie') - except Exception as e: - engine, session = login('postgresql://postgres:postgres@localhost', recreate_database=True) - return session - - def get_current_session(): return EngineStartup.get_current_session() @@ -81,6 +77,10 @@ def get_strict_redis(): class EngineStartup: @staticmethod def login_db() -> Tuple[any, sessionmaker]: + if DB_IP is not None: + connection_string = f'postgresql://{DB_USER}:{DB_PASSWORD}@{DB_IP}/saltie' + engine, session = login(connection_string) + return engine, session try: # Sql Stuff connection_string = 'postgresql:///saltie' @@ -90,6 +90,7 @@ def login_db() -> Tuple[any, sessionmaker]: try: engine, session = login('postgresql://postgres:postgres@localhost/saltie') except Exception as e: + print(e) engine, session = login('postgresql://postgres:postgres@localhost', recreate_database=True) return engine, session @@ -118,6 +119,7 @@ def get_strict_redis(): def get_current_session(): try: return current_app.config['db']() - except: + except Exception as e: + print("Error getting session", e) _session = lazy_startup() return _session() diff --git a/backend/database/utils/debug_db.py b/backend/database/utils/debug_db.py index 65ed2c047..d569cc24d 100644 --- a/backend/database/utils/debug_db.py +++ b/backend/database/utils/debug_db.py @@ -1,4 +1,4 @@ -from sqlalchemy.engine.default import DefaultDialect +from sqlalchemy.dialects.postgresql import dialect as DefaultDialect, ARRAY from sqlalchemy.sql.sqltypes import String, DateTime, NullType # python2/3 compatible. @@ -18,7 +18,11 @@ def process(value): return text(value) if not isinstance(value, str_type): value = text(value) + + if isinstance(value, list): + return text("{" + ", ".join(value) + "}") result = super_processor(value) + if isinstance(result, bytes): result = result.decode(dialect.encoding) return result @@ -33,6 +37,7 @@ class LiteralDialect(DefaultDialect): DateTime: StringLiteral, # don't format py2 long integers to NULL NullType: StringLiteral, + ARRAY: StringLiteral } diff --git a/backend/tasks/celery_tasks.py b/backend/tasks/celery_tasks.py index 701002491..d4b14704d 100644 --- a/backend/tasks/celery_tasks.py +++ b/backend/tasks/celery_tasks.py @@ -1,17 +1,16 @@ # Celery workers -import json -import time import base64 +import json import os -import requests +import time from enum import Enum, auto from typing import Dict -from requests import ReadTimeout - +import requests from celery import Celery from celery.result import AsyncResult from celery.task import periodic_task +from requests import ReadTimeout from backend.blueprints.spa_api.service_layers.leaderboards import Leaderboards from backend.database.startup import lazy_get_redis, lazy_startup @@ -22,9 +21,9 @@ from backend.tasks.add_replay import parse_replay from backend.tasks.middleware import DBTask from backend.tasks.periodic_stats import calculate_global_stats_by_playlist -from backend.utils.rlgarage_handler import RLGarageAPI from backend.tasks.utils import get_queue_length from backend.utils.cloud_handler import GCPManager +from backend.utils.rlgarage_handler import RLGarageAPI try: from backend.tasks.training_packs.task import TrainingPackCreation @@ -127,9 +126,12 @@ def calc_leaderboards(self): @periodic_task(run_every=60 * 10, base=DBTask, bind=True, priority=0) -def calc_global_dists(self): - sess = self.session() - calculate_global_stats_by_playlist() +def calc_global_dists(self, session=None): + if session is None: + sess = self.session() + else: + sess = session + calculate_global_stats_by_playlist(session) sess.close() @@ -140,6 +142,7 @@ def calc_item_stats(self, session=None): else: sess = session results = ItemStatsWrapper.create_stats(sess) + sess.close() if lazy_get_redis() is not None: lazy_get_redis().set('item_stats', json.dumps(results)) @@ -161,6 +164,7 @@ def auto_create_training_pack(self, requester_id, pack_player_id, name=None, n=1 METRICS_TRAINING_PACK_CREATION_TIME.observe( start - end ) + sess.close() return url @@ -179,6 +183,7 @@ def create_manual_training_pack(self, requester_id, players, replays, frames, na METRICS_TRAINING_PACK_CREATION_TIME.observe( start - end ) + sess.close() return url @@ -213,8 +218,9 @@ def cache_item_stats(self, session=None): print("Item", item) try: ItemStatsWrapper.get_item_usage_over_time(id_, session=session, override=True) - except: - print("Error") + except Exception as e: + print("Error", e) + session.close() class ResultState(Enum): diff --git a/backend/tasks/training_packs/task.py b/backend/tasks/training_packs/task.py index b8244e6f9..e929ea1d8 100644 --- a/backend/tasks/training_packs/task.py +++ b/backend/tasks/training_packs/task.py @@ -1,6 +1,7 @@ import datetime import logging import os +import random from sqlalchemy import desc @@ -103,7 +104,7 @@ def create_from_player(task_id, requester_id, pack_player_id, n=10, date_start=N if query.count() == 0: raise UserHasNoReplays() if date_start is not None: - last_n_games = last_n_games.all()[:100] # we don't want to overdo it, but we want to max the pack + last_n_games = random.sample(last_n_games.all(), 25) # we don't want to overdo it else: last_n_games = last_n_games[:n] # use default of last n games last_n_games = [game[0] for game in last_n_games] # gets rid of tuples diff --git a/backend/utils/psyonix_api_handler.py b/backend/utils/psyonix_api_handler.py index 2c37735a7..ab598aa06 100644 --- a/backend/utils/psyonix_api_handler.py +++ b/backend/utils/psyonix_api_handler.py @@ -5,8 +5,9 @@ import redis import requests + from backend.database.objects import Player -from backend.database.startup import lazy_startup +from backend.database.startup import get_current_session from backend.utils.braacket_connection import Braacket from backend.utils.safe_flask_globals import get_redis @@ -26,8 +27,9 @@ def get_bot_by_steam_id(steam_id): if len(steam_id) < 6: return "Allstar" else: - session = lazy_startup() - bot = session().query(Player).filter(Player.platformid == steam_id).first() + session = get_current_session() + bot = session.query(Player).filter(Player.platformid == steam_id).first() + session.close() if bot is None: return None return bot.platformname diff --git a/webapp/src/Components/Pages/HomePage.tsx b/webapp/src/Components/Pages/HomePage.tsx index f70690e77..86c087e67 100644 --- a/webapp/src/Components/Pages/HomePage.tsx +++ b/webapp/src/Components/Pages/HomePage.tsx @@ -22,9 +22,6 @@ import {LoggedInUserActions, StoreState} from "../../Redux" import {getLoggedInUser, getReplayCount} from "../../Requests/Global" import {HomePageAppBar} from "../Home/HomePageAppBar" import {HomePageFooter} from "../Home/HomePageFooter" -import {Leaderboards} from "../Home/Widgets/Leaderboards" -import {Recent} from "../Home/Widgets/Recent" -import {Twitch} from "../Home/Widgets/Twitch" import {LinkButton} from "../Shared/LinkButton" import {Logo} from "../Shared/Logo/Logo" import {Search} from "../Shared/Search" @@ -170,26 +167,26 @@ class HomePageComponent extends React.PureComponent { {isWidthUp("md", this.props.width) ? ( <> - + {/**/} - + {/**/} - + {/**/} ) : ( <> - + {/**/} - + {/**/} - + {/**/} )} diff --git a/webapp/src/Components/Player/Overview/SideBar/PlayerProfile.tsx b/webapp/src/Components/Player/Overview/SideBar/PlayerProfile.tsx index e5274489e..ac11bd372 100644 --- a/webapp/src/Components/Player/Overview/SideBar/PlayerProfile.tsx +++ b/webapp/src/Components/Player/Overview/SideBar/PlayerProfile.tsx @@ -1,6 +1,5 @@ -import * as React from "react" - import {Button, Card, CardContent, createStyles, Grid, Typography, WithStyles, withStyles} from "@material-ui/core" +import * as React from "react" import {connect} from "react-redux" import {StoreState} from "../../../../Redux" import {GroupIndicator} from "./GroupIndicator" @@ -49,6 +48,7 @@ class PlayerProfileComponent extends React.PureComponent { {player.name} {player.pastNames.length > 0 && } + diff --git a/webapp/src/Components/Player/Overview/SideBar/PlayerSideBar.tsx b/webapp/src/Components/Player/Overview/SideBar/PlayerSideBar.tsx index b7a3d8193..034fc885f 100644 --- a/webapp/src/Components/Player/Overview/SideBar/PlayerSideBar.tsx +++ b/webapp/src/Components/Player/Overview/SideBar/PlayerSideBar.tsx @@ -2,7 +2,6 @@ import {Grid} from "@material-ui/core" import * as React from "react" import {PlayerProfile} from "./PlayerProfile" import {PlayerRanksCard} from "./PlayerRanksCard" -import {PlayerStatsCard} from "./PlayerStats/PlayerStatsCard" interface Props { player: Player @@ -16,7 +15,7 @@ export class PlayerSideBar extends React.PureComponent { - + {/**/} diff --git a/webapp/src/Components/Player/PlayerOverview.tsx b/webapp/src/Components/Player/PlayerOverview.tsx index e96014923..db8f401d1 100644 --- a/webapp/src/Components/Player/PlayerOverview.tsx +++ b/webapp/src/Components/Player/PlayerOverview.tsx @@ -5,8 +5,6 @@ import {isWidthDown, isWidthUp, WithWidth} from "@material-ui/core/withWidth" import * as React from "react" import {OverviewMatchHistory} from "./Overview/MatchHistory/OverviewMatchHistory" import {PlayerMatchHistoryCard} from "./Overview/MatchHistory/PlayerMatchHistoryCard" -import {PlayerPlayStyle} from "./Overview/PlayStyle/PlayerPlayStyle" -import {PlayerPlayStyleCard} from "./Overview/PlayStyle/PlayerPlayStyleCard" import {PlayStyleActions} from "./Overview/PlayStyle/PlayStyleActions" import {PlayerSideBar} from "./Overview/SideBar/PlayerSideBar" @@ -39,13 +37,13 @@ class PlayerOverviewComponent extends React.PureComponent { } const playerSideBar = - const playerPlayStyle = ( - - ) + // const playerPlayStyle = ( + // + // ) const playerMatchHistory = ( ) @@ -59,15 +57,15 @@ class PlayerOverviewComponent extends React.PureComponent { - - {playerPlayStyle} - + {/**/} + {/* {playerPlayStyle}*/} + {/**/} @@ -103,7 +101,7 @@ class PlayerOverviewComponent extends React.PureComponent { handleWinsLossesChange={this.handleWinsLossesChange} /> - {playerPlayStyle} + {/*{playerPlayStyle}*/} )} {this.state.selectedMobileTab === "Match History" && playerMatchHistory} diff --git a/webapp/src/Components/Replay/ReplayTabs.tsx b/webapp/src/Components/Replay/ReplayTabs.tsx index 4a194c52a..d2a633ecc 100644 --- a/webapp/src/Components/Replay/ReplayTabs.tsx +++ b/webapp/src/Components/Replay/ReplayTabs.tsx @@ -93,16 +93,8 @@ class ReplayTabsComponent extends React.PureComponent { - {this.props.loggedInUser && this.props.loggedInUser.beta ? ( - - ) : ( - - )} - {this.props.loggedInUser && this.props.loggedInUser.beta ? ( - - ) : ( - - )} + + {this.props.loggedInUser && this.props.loggedInUser.beta ? ( ) : ( diff --git a/webapp/src/Components/Replay/ReplayTeamCard/ReplayTeamCard.tsx b/webapp/src/Components/Replay/ReplayTeamCard/ReplayTeamCard.tsx index 9714a893f..ba32aa163 100644 --- a/webapp/src/Components/Replay/ReplayTeamCard/ReplayTeamCard.tsx +++ b/webapp/src/Components/Replay/ReplayTeamCard/ReplayTeamCard.tsx @@ -46,7 +46,7 @@ class ReplayTeamCardComponent extends React.PureComponent { {replay.players .filter((player) => player.isOrange === isOrange) .map((player) => ( - + ))} diff --git a/webapp/src/Components/Replay/ReplayTeamCard/TeamCardPlayer.tsx b/webapp/src/Components/Replay/ReplayTeamCard/TeamCardPlayer.tsx index a8e7eda41..8d36fddb5 100644 --- a/webapp/src/Components/Replay/ReplayTeamCard/TeamCardPlayer.tsx +++ b/webapp/src/Components/Replay/ReplayTeamCard/TeamCardPlayer.tsx @@ -12,10 +12,12 @@ import { import * as React from "react" import {Link, LinkProps} from "react-router-dom" import {PLAYER_PAGE_LINK} from "../../../Globals" +import {GroupIndicator} from "../../Player/Overview/SideBar/GroupIndicator" import {CameraSettingsDisplay} from "./CameraSettingsDisplay" import {LoadoutDisplay} from "./LoadoutDisplay" interface Props { + groupMap: any player: ReplayPlayer } @@ -37,7 +39,7 @@ export class TeamCardPlayer extends React.PureComponent { } public render() { - const {player} = this.props + const {player, groupMap} = this.props const carButton = ( @@ -64,6 +66,7 @@ export class TeamCardPlayer extends React.PureComponent { style={{padding: "0 64px 0 0"}} /> + {groupMap && } {carButton} {cameraButton} diff --git a/webapp/src/Components/Shared/SideBar.tsx b/webapp/src/Components/Shared/SideBar.tsx index 231441c70..c90fe6101 100644 --- a/webapp/src/Components/Shared/SideBar.tsx +++ b/webapp/src/Components/Shared/SideBar.tsx @@ -11,7 +11,6 @@ import Info from "@material-ui/icons/Info" import Search from "@material-ui/icons/Search" import ShowChart from "@material-ui/icons/ShowChart" import SportsSoccer from "@material-ui/icons/SportsSoccer" -import TableChart from "@material-ui/icons/TableChart" import * as React from "react" import {connect} from "react-redux" import {Link, LinkProps} from "react-router-dom" @@ -21,7 +20,6 @@ import { EXPLANATIONS_LINK, GITHUB_LINK, GLOBAL_STATS_LINK, - LEADERBOARDS_LINK, PATREON_LINK, PLAYER_COMPARE_PAGE_LINK, REPLAYS_GROUP_PAGE_LINK, @@ -76,12 +74,12 @@ class SideBarComponent extends React.PureComponent { Player - + {/* Leaderboards - + */} diff --git a/webapp/src/Models/Replay/Replay.ts b/webapp/src/Models/Replay/Replay.ts index e0cc083fd..11d0388c7 100644 --- a/webapp/src/Models/Replay/Replay.ts +++ b/webapp/src/Models/Replay/Replay.ts @@ -25,6 +25,7 @@ export interface Replay { visibility: GameVisibility ranks: number[] mmrs: number[] + groupMap: any } export interface CompactReplay { diff --git a/webapp/src/Requests/Mock.ts b/webapp/src/Requests/Mock.ts index 156bf3f09..43c534ac6 100644 --- a/webapp/src/Requests/Mock.ts +++ b/webapp/src/Requests/Mock.ts @@ -535,7 +535,8 @@ export const MOCK_REPLAY_1: Replay = { tags: [], visibility: GameVisibility.PUBLIC, ranks: [14, 15, 14, 14], - mmrs: [1000, 1100, 1050, 1025] + mmrs: [1000, 1100, 1050, 1025], + groupMap: {} } export const MOCK_REPLAY_2 = { @@ -709,5 +710,6 @@ export const MOCK_REPLAY_2 = { } } ], - tags: [] + tags: [], + groupMap: {} }