mirror of
https://github.com/RaidMax/IW4M-Admin.git
synced 2025-06-09 23:00:57 -05:00
huge commit for webfront facelift
This commit is contained in:
@ -3,60 +3,71 @@
|
||||
var loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
}
|
||||
|
||||
<div class="row d-none d-lg-block ">
|
||||
<h4 class="pb-2 text-center col-12">@ViewBag.Title</h4>
|
||||
<div class="mr-auto ml-auto col-12 col-lg-8 border-bottom">
|
||||
<div class="row pt-2 pb-2 bg-primary">
|
||||
<div class="col-5 ">@loc["WEBFRONT_PENALTY_TEMPLATE_NAME"]</div>
|
||||
<div class="col-4">@loc["WEBFRONT_PROFILE_LEVEL"]</div>
|
||||
<div class="col-3 text-right">@loc["WEBFRONT_SEARCH_LAST_CONNECTED"]</div>
|
||||
</div>
|
||||
<!-- desktop -->
|
||||
<div class="content mt-0">
|
||||
<h2 class="content-title mt-20">@ViewBag.ResultCount result(s) for <span class="badge badge-primary font-size-18">@ViewBag.SearchTerm</span></h2>
|
||||
|
||||
<table class="table d-none d-md-table">
|
||||
<thead>
|
||||
<tr class="bg-primary text-light">
|
||||
<td>@loc["WEBFRONT_PENALTY_TEMPLATE_NAME"]</td>
|
||||
<td>@loc["WEBFRONT_PROFILE_LEVEL"]</td>
|
||||
<td class="text-right">@loc["WEBFRONT_SEARCH_LAST_CONNECTED"]</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var client in Model)
|
||||
{
|
||||
<div class="row pt-2 pb-2 bg-dark">
|
||||
<div class="col-5">
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@client.ClientId">
|
||||
<tr class="bg-dark-dm bg-light-lm">
|
||||
<td class="col-5">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@client.ClientId">
|
||||
<color-code value="@client.Name"></color-code>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
@if (!ViewBag.Authorized && ViewBag.EnablePrivilegedUserPrivacy)
|
||||
{
|
||||
<div class="col-4 level-color-0">@loc["GLOBAL_PERMISSION_USER"]</div>
|
||||
<td class="col-3 level-color-0">@loc["GLOBAL_PERMISSION_USER"]</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="col-4 level-color-@client.LevelInt">@client.Level</div>
|
||||
<td class="col-3 level-color-@client.LevelInt">@client.Level</td>
|
||||
}
|
||||
<div class="col-3 text-right">@client.LastConnectionText</div>
|
||||
</div>
|
||||
<td class="col-4 text-right">@client.LastConnection.HumanizeForCurrentCulture()</td>
|
||||
</tr>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-lg-none">
|
||||
<div class="w-100 bg-primary text-center h3 mb-0 p-3" style="border-bottom: 1px solid #222">@ViewBag.Title</div>
|
||||
@foreach (var client in Model)
|
||||
{
|
||||
<div class="col-5 bg-primary font-weight-bold" style="border-bottom: 1px solid #222">
|
||||
<div class="p-2">@loc["WEBFRONT_PENALTY_TEMPLATE_NAME"]</div>
|
||||
<div class="p-2">@loc["WEBFRONT_PROFILE_LEVEL"]</div>
|
||||
<div class="p-2">@loc["WEBFRONT_SEARCH_LAST_CONNECTED"]</div>
|
||||
</div>
|
||||
<div class="col-7 bg-dark border-bottom">
|
||||
<div class="p-2">
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@client.ClientId" class="link-inverse">
|
||||
<color-code value="@client.Name"></color-code>
|
||||
</a>
|
||||
</div>
|
||||
@if (!ViewBag.Authorized && ViewBag.EnablePrivilegedUserPrivacy)
|
||||
{
|
||||
<div class="p-2 level-color-0">@loc["GLOBAL_PERMISSION_USER"]</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="p-2 level-color-@client.LevelInt">@client.Level</div>
|
||||
}
|
||||
<div class="p-2 text-white-50">@client.LastConnectionText</div>
|
||||
</div>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<!--- mobile -->
|
||||
<table class="table bg-dark-dm bg-light-lm d-md-none">
|
||||
<tbody>
|
||||
@foreach (var client in Model)
|
||||
{
|
||||
<tr class="d-flex">
|
||||
<td class="bg-primary text-light">
|
||||
<div>@loc["WEBFRONT_PENALTY_TEMPLATE_NAME"]</div>
|
||||
<div>@loc["WEBFRONT_PROFILE_LEVEL"]</div>
|
||||
<div>@loc["WEBFRONT_SEARCH_LAST_CONNECTED"]</div>
|
||||
</td>
|
||||
<td class="flex-grow">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@client.ClientId" class="link-inverse">
|
||||
<color-code value="@client.Name"></color-code>
|
||||
</a>
|
||||
@if (!ViewBag.Authorized && ViewBag.EnablePrivilegedUserPrivacy)
|
||||
{
|
||||
<div class="p-2 level-color-0">@loc["GLOBAL_PERMISSION_USER"]</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="p-2 level-color-@client.LevelInt">@client.Level</div>
|
||||
}
|
||||
<div>@client.LastConnection.HumanizeForCurrentCulture()</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -1,30 +1,33 @@
|
||||
@using SharedLibraryCore.Dtos.Meta.Responses
|
||||
@model SharedLibraryCore.Helpers.ResourceQueryHelperResult<MessageResponse>
|
||||
|
||||
<div class="content mt-0">
|
||||
@if (ViewBag.Error != null)
|
||||
{
|
||||
<h4 class="text-red">@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_INVALID_QUERY"], ViewBag.Error.Message)</h4>
|
||||
<h2 class="content-title text-red mt-20">@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_INVALID_QUERY"], ViewBag.Error.Message)</h2>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<h4 class="pb-3 text-center">@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_STATS_MESSAGES_FOUND"], Model.TotalResultCount.ToString("N0"))</h4>
|
||||
<h2 class="content-title mt-20">@Html.Raw(Utilities.FormatExt(ViewBag.Localization["WEBFRONT_STATS_MESSAGES_FOUND"], $"<span class=\"badge badge-primary font-size-18\">{Model.TotalResultCount.ToString("N0")}</span>"))</h2>
|
||||
|
||||
<table class="table table-striped table-hover">
|
||||
<table class="table bg-dark-dm bg-light-lm rounded" style="table-layout: fixed">
|
||||
<thead class="d-none d-lg-table-header-group">
|
||||
<tr class="bg-primary pt-2 pb-2">
|
||||
<th scope="col">@ViewBag.Localization["WEBFRONT_PENALTY_TEMPLATE_ADMIN"]</th>
|
||||
<th scope="col">@ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"]</th>
|
||||
<th scope="col">@ViewBag.Localization["WEBFRONT_STATS_MESSAGE_SERVER_NAME"]</th>
|
||||
<th scope="col" class="text-right">@ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"]</th>
|
||||
<tr class="bg-primary text-light">
|
||||
<th colspan="20%">@ViewBag.Localization["WEBFRONT_PENALTY_TEMPLATE_ADMIN"]</th>
|
||||
<th colspan="45%">@ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"]</th>
|
||||
<th colspan="20%">@ViewBag.Localization["WEBFRONT_STATS_MESSAGE_SERVER_NAME"]</th>
|
||||
<th colspan="15%" class="text-right">@ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="message_table_body" class="border-bottom bg-dark">
|
||||
<tbody id="message_table_body">
|
||||
<partial name="~/Views/Client/Message/_Item.cshtml" model="@Model.Results" />
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<span id="load_more_messages_button" class="loader-load-more oi oi-chevron-bottom text-center text-primary w-100 h3 pb-0 mb-0 d-none d-lg-block"></span>
|
||||
<div id="loaderLoad" class="mt-10 m-auto text-center d-none d-lg-block">
|
||||
<i class="loader-load-more oi oi-chevron-bottom "></i>
|
||||
</div>
|
||||
|
||||
@section scripts {
|
||||
<environment include="Development">
|
||||
@ -36,4 +39,5 @@ else
|
||||
});
|
||||
</script>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
@ -5,64 +5,56 @@
|
||||
{
|
||||
<!-- desktop -->
|
||||
<tr class="d-none d-lg-table-row">
|
||||
<td>
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@message.ClientId" class="link-inverse">
|
||||
<td colspan="20%" class="text-break">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@message.ClientId" class="link-inverse">
|
||||
<color-code value="@message.ClientName"></color-code>
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-light w-50 text-break">
|
||||
<td colspan="45%" class="text-break">
|
||||
@if (message.IsHidden && !ViewBag.Authorized)
|
||||
{
|
||||
<color-code value="@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], message.HiddenMessage)"></color-code>
|
||||
<color-code value="@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], message.HiddenMessage)"></color-code>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@message.Message"></color-code>
|
||||
}
|
||||
</td>
|
||||
<td class="text-light">
|
||||
<td colspan="20%" class="text-break">
|
||||
<color-code value="@(message.ServerName ?? "--")"></color-code>
|
||||
</td>
|
||||
<td class="text-right text-light">
|
||||
<td colspan="15%" class="text-right text-break">
|
||||
@message.When
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- mobile -->
|
||||
<tr class="d-table-row d-lg-none bg-dark">
|
||||
<th scope="row" class="bg-primary">@ViewBag.Localization["WEBFRONT_PENALTY_TEMPLATE_ADMIN"]</th>
|
||||
<td class="text-light">
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@message.ClientId" class="link-inverse">
|
||||
<tr class="d-flex d-lg-none">
|
||||
<td class="bg-primary text-light">
|
||||
<div>@ViewBag.Localization["WEBFRONT_PENALTY_TEMPLATE_ADMIN"]</div>
|
||||
<div>@ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"]</div>
|
||||
<div>@ViewBag.Localization["WEBFRONT_STATS_MESSAGE_SERVER_NAME"]</div>
|
||||
<div>@ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"]</div>
|
||||
</td>
|
||||
<td class="flex-fill">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@message.ClientId">
|
||||
<color-code value="@message.ClientName"></color-code>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<div>
|
||||
@if (message.IsHidden && !ViewBag.Authorized)
|
||||
{
|
||||
<color-code value="@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], message.HiddenMessage)"></color-code>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@message.Message"></color-code>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<color-code value="@(message.ServerName ?? "--")"></color-code>
|
||||
</div>
|
||||
<div> @message.When</div>
|
||||
|
||||
<tr class="d-table-row d-lg-none bg-dark">
|
||||
<th scope="row" class="bg-primary">@ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"]</th>
|
||||
<td class="text-light">
|
||||
@if (message.IsHidden && !ViewBag.Authorized)
|
||||
{
|
||||
<color-code value="@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], message.HiddenMessage)"></color-code>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@message.Message"></color-code>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="d-table-row d-lg-none bg-dark">
|
||||
<th scope="row" class="bg-primary">@ViewBag.Localization["WEBFRONT_STATS_MESSAGE_SERVER_NAME"]</th>
|
||||
<td class="text-light">
|
||||
<color-code value="@(message.ServerName ?? "--")"></color-code>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="d-table-row d-lg-none bg-dark">
|
||||
<th scope="row" class="bg-primary" style="border-bottom: 1px solid #222">@ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"]</th>
|
||||
<td class="text-light mb-2 border-bottom">
|
||||
@message.When
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
@ -1,24 +1,31 @@
|
||||
@model Dictionary<SharedLibraryCore.Database.Models.EFClient.Permission, IList<SharedLibraryCore.Dtos.ClientInfo>>
|
||||
<div class="content mt-0">
|
||||
<h4 class="content-title mt-20">@ViewBag.Title</h4>
|
||||
|
||||
<h4 class="pb-3 text-center ">@ViewBag.Title</h4>
|
||||
|
||||
<div class="row border-bottom">
|
||||
@{
|
||||
foreach (var key in Model.Keys)
|
||||
{
|
||||
<div class="col-12 bg-primary pt-2 pb-2">
|
||||
@Utilities.ToLocalizedLevelName(key)
|
||||
</div>
|
||||
|
||||
<div class="col-12 bg-dark pt-2 pb-2">
|
||||
@foreach (var client in Model[key])
|
||||
{
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@client.ClientId">
|
||||
<color-code value="@client.Name"></color-code>
|
||||
</a>
|
||||
<br />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@foreach (var key in Model.Keys)
|
||||
{
|
||||
<table class="table mb-20">
|
||||
<thead>
|
||||
<tr class="level-bgcolor-@((int)key)">
|
||||
<th class="text-light">@key.ToLocalizedLevelName()</th>
|
||||
<th class="text-right font-weight-bold">Last Connected</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var client in Model[key].OrderByDescending(client => client.LastConnection))
|
||||
{
|
||||
<tr class="bg-dark-dm bg-light-lm">
|
||||
<td>
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@client.ClientId">
|
||||
<color-code value="@client.Name"></color-code>
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
@client.LastConnection.HumanizeForCurrentCulture()
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
</div>
|
||||
|
@ -1,6 +1,8 @@
|
||||
@using SharedLibraryCore.Interfaces
|
||||
@using Data.Models
|
||||
@using Data.Models.Client
|
||||
@using WebfrontCore.Permissions
|
||||
@using WebfrontCore.ViewModels
|
||||
@model SharedLibraryCore.Dtos.PlayerInfo
|
||||
@{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(Model.Name.ToUpper(), "[A-Z]").Value;
|
||||
@ -11,70 +13,39 @@
|
||||
var isTempBanned = Model.ActivePenalty?.Type == EFPenalty.PenaltyType.TempBan;
|
||||
var translationKey = $"WEBFRONT_PROFILE_{Model.ActivePenalty?.Type.ToString().ToUpper()}_INFO";
|
||||
var ignoredMetaTypes = new[] { MetaType.Information, MetaType.Other, MetaType.QuickMessage };
|
||||
|
||||
string ClassForPenaltyType(EFPenalty.PenaltyType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
EFPenalty.PenaltyType.Ban => "alert-danger",
|
||||
EFPenalty.PenaltyType.Flag => "alert-secondary",
|
||||
EFPenalty.PenaltyType.TempBan => "alert-secondary",
|
||||
_ => "alert"
|
||||
};
|
||||
}
|
||||
|
||||
string ClassForProfileBackground()
|
||||
{
|
||||
return (ViewBag.PermissionsSet as IEnumerable<string>).HasPermission(WebfrontEntity.ClientLevel, WebfrontPermission.Read) ? $"level-bgcolor-{Model.LevelInt}" : "level-bgcolor-0";
|
||||
}
|
||||
}
|
||||
|
||||
<div id="profile_wrapper" class="pb-3 row d-flex flex-column flex-lg-row">
|
||||
<!-- Initial/Avatar Column -->
|
||||
<div id="profile_avatar" class="d-block d-lg-inline-flex flex-column mr-auto ml-auto mr-lg-0 ml-lg-0 justify-content-center text-center level-bgcolor-@(!ViewBag.Authorized && ViewBag.EnablePrivilegedUserPrivacy ? "0" : Model.LevelInt.ToString()) @(isTempBanned ? "penalties-bgcolor-tempban" : "")" style="background-image:url('@string.Format("https://gravatar.com/avatar/{0}?size=168&default=blank&rating=pg", gravatarUrl)')">
|
||||
@if (string.IsNullOrEmpty(gravatarUrl))
|
||||
{
|
||||
<span class="profile-shortcode">@shortCode</span>
|
||||
}
|
||||
</div>
|
||||
<!-- Name/Level Column -->
|
||||
<div class="w-50 d-block d-lg-inline-flex flex-column flex-fill text-center text-lg-left pb-3 pb-lg-0 pt-3 pt-lg-0 pl-3 pr-3 ml-auto mr-auto" style="overflow-wrap: anywhere">
|
||||
<div class="mt-n2 d-block d-lg-inline-flex @(ViewBag.Authorized ? "" : "flex-fill")">
|
||||
<div id="profile_name" class="client-name h1 mb-0">
|
||||
<color-code value="@Model.Name"></color-code>
|
||||
</div>
|
||||
@if (ViewBag.Authorized)
|
||||
{
|
||||
<div id="profile_aliases_btn" class="oi oi-caret-bottom h3 ml-0 ml-lg-2 mb-0 pt-lg-2 mt-lg-1"></div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (ViewBag.Authorized)
|
||||
{
|
||||
<div class="d-flex flex-row justify-content-start flex-fill flex-column flex-lg-row mr-lg-2 mb-2 mb-md-0">
|
||||
<div class="ip-lookup-profile align-self-center mr-0 mr-lg-2 ml-lg-n1" data-ip="@Model.IPAddress"></div>
|
||||
<div id="ip_lookup_country" class="h4 mb-2 mb-lg-0 align-self-center text-muted"></div>
|
||||
</div>
|
||||
|
||||
<div id="profile_aliases" class="text-muted pt-0 pt-lg-2 pb-2">
|
||||
@foreach (var linked in Model.LinkedAccounts)
|
||||
{
|
||||
<div>
|
||||
@Html.ActionLink(linked.Value.ToString("X"), "ProfileAsync", "Client", new { id = linked.Key }, new { @class = "link-inverse" })
|
||||
</div>
|
||||
}
|
||||
@foreach (var alias in Model.Aliases)
|
||||
{
|
||||
<div>
|
||||
<color-code value="@alias"></color-code>
|
||||
</div>
|
||||
}
|
||||
|
||||
@foreach (var ip in Model.IPs)
|
||||
{
|
||||
<div>
|
||||
<a class="ip-locate-link" href="#" data-ip="@ip">@ip</a>
|
||||
<a href="/Client/FindAsync?clientName=@ip" class="oi oi-magnifying-glass text-muted"></a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (Model.ActivePenalty != null && (Model.ActivePenalty.Type != EFPenalty.PenaltyType.Flag || ViewBag.Authorized))
|
||||
{
|
||||
<div class="font-weight-bold h4 mb-0 penalties-color-@Model.ActivePenalty.Type.ToString().ToLower()">
|
||||
<div class="content row mt-20">
|
||||
<div class="col-12 col-lg-9 col-xl-10">
|
||||
@if (Model.ActivePenalty != null)
|
||||
{
|
||||
<has-permission entity="ClientLevel" required-permission="Read">
|
||||
<div class="alert @ClassForPenaltyType(Model.ActivePenalty.Type) mt-10 mb-10" role="alert">
|
||||
@foreach (var result in Utilities.SplitTranslationTokens(translationKey))
|
||||
{
|
||||
switch (result.MatchValue)
|
||||
{
|
||||
case "reason":
|
||||
<span class="text-white font-weight-lighter">@(ViewBag.Authorized ? !string.IsNullOrEmpty(Model.ActivePenalty.AutomatedOffense) && Model.ActivePenalty.Type != EFPenalty.PenaltyType.Warning ? Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.ActivePenalty.AutomatedOffense) : Model.ActivePenalty.Offense.StripColors() : Model.ActivePenalty.Offense.StripColors())</span>
|
||||
<span class="text-light-dm font-weight-lighter">@(ViewBag.Authorized ? !string.IsNullOrEmpty(Model.ActivePenalty.AutomatedOffense) && Model.ActivePenalty.Type != EFPenalty.PenaltyType.Warning ? Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.ActivePenalty.AutomatedOffense) : Model.ActivePenalty.Offense.StripColors() : Model.ActivePenalty.Offense.StripColors())</span>
|
||||
break;
|
||||
case "time":
|
||||
<span class="text-white font-weight-lighter">
|
||||
<span class="text-light-dm font-weight-lighter">
|
||||
@((Model.ActivePenalty.Expires.Value - DateTime.UtcNow).HumanizeForCurrentCulture())
|
||||
</span>
|
||||
break;
|
||||
@ -84,121 +55,261 @@
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
</has-permission>
|
||||
}
|
||||
|
||||
<h2 class="content-title mb-10">Player Profile</h2>
|
||||
|
||||
<div id="profile_wrapper" class="mb-10 mt-10">
|
||||
|
||||
<!-- online status indicator -->
|
||||
@if (Model.Online)
|
||||
{
|
||||
if (!ViewBag.Authorized && ViewBag.EnablePrivilegedUserPrivacy)
|
||||
{
|
||||
<div id="profile_level" class="font-weight-bold h4 mb-0 level-color-0">
|
||||
@ViewBag.Localization["GLOBAL_PERMISSION_USER"]
|
||||
<div class="bg-success rounded-circle position-absolute status-indicator z-20 mt-10 ml-10" data-toggle="tooltip" data-placement="bottom" data-title="Client is online"></div>
|
||||
<div class="bg-success rounded-circle position-absolute status-indicator with-ripple z-10 mt-10 ml-10"></div>
|
||||
}
|
||||
|
||||
<!-- main profile row -->
|
||||
<div class="card p-20 ml-0 mr-0 mt-0 mb-10 d-flex flex-fill flex-wrap flex-column flex-md-row justify-content-center">
|
||||
<div class="d-flex flex-column flex-md-row">
|
||||
<div id="profile_avatar" class="w-150 w-md-100 h-150 h-md-100 mt-10 mb-10 d-flex justify-content-center align-self-center rounded @ClassForProfileBackground() @(isTempBanned ? "penalties-bgcolor-tempban" : "")" style="background-image:url('@($"https://gravatar.com/avatar/{gravatarUrl}?size=168&default=blank&rating=pg")">
|
||||
@if (string.IsNullOrEmpty(gravatarUrl))
|
||||
{
|
||||
<div class="profile-shortcode align-self-center text-dark-lm">@shortCode</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
<div class="d-flex flex-column align-self-center ml-20 mr-20 mt-10 mb-10 mt-md-0 mb-md-0 text-center text-md-left">
|
||||
<!-- name -->
|
||||
<div id="profile_name">
|
||||
<span class="font-size-20 font-weight-medium">
|
||||
<color-code value="@Model.Name"></color-code>
|
||||
</span>
|
||||
<has-permission entity="MetaAliasUpdate" required-permission="Read">
|
||||
<div class="dropdown dropright with-arrow">
|
||||
<div data-toggle="dropdown" id="profileAliasHistory" aria-haspopup="true" aria-expanded="false">
|
||||
@if (Model.Aliases.Any())
|
||||
{
|
||||
<i class="oi oi-caret-bottom font-size-12" aria-hidden="true"></i>
|
||||
}
|
||||
</div>
|
||||
|
||||
else
|
||||
{
|
||||
<div id="profile_level" class="font-weight-bold h4 mb-0 level-color-@Model.LevelInt">
|
||||
@Model.Level
|
||||
<div class="dropdown-menu @(Model.Aliases.Where(alias => !alias.Item1.Contains(" ")).Max(alias => (int?)alias.Item1.Length) >= 15 ? "w-250" : "") " aria-labelledby="profileAliasHistory">
|
||||
@foreach (var (alias, dateAdded) in Model.Aliases.OrderByDescending(alias => alias.Item2).Take(15))
|
||||
{
|
||||
<a asp-controller="Client" asp-action="Find" asp-route-clientName="@alias" class="dropdown-item" data-toggle="tooltip" data-title="@dateAdded.HumanizeForCurrentCulture()">
|
||||
<i class="oi oi-magnifying-glass text-muted mr-5"></i>
|
||||
<color-code value="@alias"></color-code>
|
||||
</a>
|
||||
}
|
||||
@if (Model.Aliases.Count > 15)
|
||||
{
|
||||
<div class="dropdown-divider"></div>
|
||||
<span class="dropdown-item bg-dark-dm bg-light-lm">...and @(Model.Aliases.Count - 15) more</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</has-permission>
|
||||
</div>
|
||||
<!-- permission level -->
|
||||
<has-permission entity="ClientLevel" required-permission="Read">
|
||||
<div class="align-self-center align-self-md-start font-weight-bold font-size-16 level-color-@Model.LevelInt">
|
||||
<div class="d-flex flex-row">
|
||||
<span>@Model.Level</span>
|
||||
</div>
|
||||
</div>
|
||||
</has-permission>
|
||||
|
||||
<!-- guid -->
|
||||
<has-permission entity="ClientGuid" required-permission="Read">
|
||||
<div class="dropdown dropup with-arrow">
|
||||
<div class="text-muted" data-toggle="dropdown" id="altGuidFormatsDropdown" aria-haspopup="true" aria-expanded="false">@Model.NetworkId.ToString("X")</div>
|
||||
<div class="dropdown-menu" aria-labelledby="altGuidFormatsDropdown">
|
||||
<div class="p-10 font-size-12">
|
||||
<div class="">Alternative Formats</div>
|
||||
<div class="dropdown-divider mt-5 mb-5"></div>
|
||||
<div class="text-muted font-weight-lighter">@((ulong)Model.NetworkId)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</has-permission>
|
||||
|
||||
<!-- ip address -->
|
||||
<div class="align-self-center align-self-md-start d-flex flex-row">
|
||||
<span class="text-muted mr-5">@Model.IPAddress</span>
|
||||
<has-permission entity="MetaAliasUpdate" required-permission="Read">
|
||||
<div class="dropdown dropright with-arrow">
|
||||
<div data-toggle="dropdown" id="profileIPAddressHistory" aria-haspopup="true" aria-expanded="false">
|
||||
@if (Model.IPs.Any(ip => !string.IsNullOrEmpty(ip.Item1)))
|
||||
{
|
||||
<i class="oi oi-caret-bottom font-size-12" aria-hidden="true"></i>
|
||||
}
|
||||
</div>
|
||||
<div class="dropdown-menu" aria-labelledby="profileAliasHistory">
|
||||
@foreach (var (ip, dateAdded) in Model.IPs.OrderByDescending(ip => ip.Item2).Take(15))
|
||||
{
|
||||
<a asp-controller="Client" asp-action="Find" asp-route-clientName="@ip" class="dropdown-item" data-toggle="tooltip" data-title="@dateAdded.HumanizeForCurrentCulture()">
|
||||
<i class="oi oi-magnifying-glass text-muted mr-5"></i>
|
||||
<color-code value="@ip"></color-code>
|
||||
</a>
|
||||
}
|
||||
@if (Model.IPs.Count > 15)
|
||||
{
|
||||
<div class="dropdown-divider"></div>
|
||||
<span class="dropdown-item bg-dark-dm bg-light-lm">...and @(Model.IPs.Count - 15) more</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</has-permission>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pr-lg-0 text-center text-lg-right">
|
||||
@if (ViewBag.Authorized)
|
||||
{
|
||||
@if (!isPermBanned)
|
||||
{
|
||||
<div class="profile-action oi oi-flag h3 ml-2 @(isFlagged ? "text-secondary" : "text-success")" data-action="@(isFlagged ? "unflag" : "flag")" aria-hidden="true"></div>
|
||||
}
|
||||
|
||||
@if (Model.LevelInt < (int)ViewBag.User.Level && !Model.HasActivePenalty)
|
||||
{
|
||||
<div id="profile_action_ban_btn" class="profile-action oi oi-lock-unlocked text-success h3 ml-2" title="Ban Client" data-action="ban" aria-hidden="true"></div>
|
||||
}
|
||||
|
||||
@if (Model.LevelInt < (int)ViewBag.User.Level && Model.HasActivePenalty)
|
||||
{
|
||||
@if (isTempBanned)
|
||||
{
|
||||
<div id="profile_action_ban_btn" class="profile-action oi oi-lock-unlocked text-success h3 ml-2" title="Ban Client" data-action="ban" aria-hidden="true"></div>
|
||||
<div id="profile_action_unban_btn" class="profile-action oi oi-lock-locked penalties-color-tempban h3 ml-2" title="Unban Client" data-action="unban" aria-hidden="true"></div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div id="profile_action_unban_btn" class="profile-action oi oi-lock-locked text-danger h3 ml-2" title="Unban Client" data-action="unban" aria-hidden="true"></div>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@if (Model.LevelInt != -1)
|
||||
{
|
||||
<div id="profile_action_edit_btn" class="profile-action oi oi-cog text-muted h3 ml-2" title="Client Options" data-action="edit" aria-hidden="true"></div>
|
||||
}
|
||||
}
|
||||
@if (ViewBag.UseNewStats)
|
||||
{
|
||||
<a asp-controller="ClientStatistics" asp-action="Advanced" asp-route-id="@Model.ClientId" class="oi oi-graph text-primary h3 ml-2" title="Stats" aria-hidden="true"></a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="profile_info" class="row d-block d-lg-flex flex-row border-bottom border-top pt-2 pb-2">
|
||||
<partial name="Meta/_Information.cshtml" model="@Model.Meta"/>
|
||||
</div>
|
||||
|
||||
<div class="row border-bottom">
|
||||
<div class="d-md-flex flex-fill">
|
||||
<div class="bg-dark p-2 pl-3 pr-3 text-center text-muted border-0 align-self-stretch align-middle" id="filter_meta_container_button">
|
||||
<span class="text-primary" id="meta_filter_dropdown_icon">▼</span>
|
||||
<a>@ViewBag.Localization["WEBFRONT_CLIENT_META_FILTER"]</a>
|
||||
</div>
|
||||
<div id="filter_meta_container" class="d-none d-md-flex flex-md-fill flex-md-wrap">
|
||||
@{
|
||||
const int defaultTabCount = 5;
|
||||
var metaTypes = Enum.GetValues(typeof(MetaType))
|
||||
.Cast<MetaType>()
|
||||
.Where(type => !ignoredMetaTypes.Contains(type))
|
||||
.OrderByDescending(type => type == MetaType.All)
|
||||
.ToList();
|
||||
var selectedMeta = metaTypes.FirstOrDefault(meta => metaTypes.IndexOf(Model.MetaFilterType ?? MetaType.All) >= defaultTabCount && meta != MetaType.All && meta == Model.MetaFilterType);
|
||||
}
|
||||
@foreach (var type in metaTypes.Take(defaultTabCount - 1).Append(selectedMeta == MetaType.Other ? metaTypes[defaultTabCount - 1] : selectedMeta))
|
||||
{
|
||||
<a asp-action="ProfileAsync" asp-controller="Client"
|
||||
class="meta-filter nav-link p-2 pl-3 pr-3 text-center @(Model.MetaFilterType.HasValue && Model.MetaFilterType.Value.ToString() == type.ToString() ? "btn-primary text-white" : "text-muted")"
|
||||
asp-route-id="@Model.ClientId"
|
||||
asp-route-metaFilterType="@type"
|
||||
data-meta-type="@type">
|
||||
@type.ToTranslatedName()
|
||||
</a>
|
||||
}
|
||||
<div class="d-md-none" id="additional_meta_filter">
|
||||
@foreach (var type in (selectedMeta == MetaType.Other ? metaTypes.Skip(defaultTabCount) : metaTypes.Skip(defaultTabCount).Append(metaTypes[defaultTabCount - 1])).Where(meta => selectedMeta == MetaType.Other || meta != selectedMeta))
|
||||
{
|
||||
<a asp-action="ProfileAsync" asp-controller="Client"
|
||||
class="meta-filter nav-link p-2 pl-3 pr-3 text-center @(Model.MetaFilterType.HasValue && Model.MetaFilterType.Value.ToString() == type.ToString() ? "btn-primary text-white" : "text-muted")"
|
||||
asp-route-id="@Model.ClientId"
|
||||
asp-route-metaFilterType="@type"
|
||||
data-meta-type="@type">
|
||||
@type.ToTranslatedName()
|
||||
<div class="flex-fill d-flex justify-content-center justify-content-md-end mt-10 mt-md-0">
|
||||
<!-- country flag -->
|
||||
<div id="ipGeoDropdown" class="dropdown dropleft with-arrow align-self-center">
|
||||
<a href="#" data-toggle="dropdown" id="avatar-popover-toggle" aria-haspopup="true" aria-expanded="false">
|
||||
@if (!string.IsNullOrEmpty(Model.GeoLocationInfo.CountryCode))
|
||||
{
|
||||
<div class="ip-lookup-profile w-100 rounded align-self-center" style="height:5rem;background-image: url('https://flagcdn.com/w80/@(Model.GeoLocationInfo.CountryCode.ToLower()).png')" data-ip="@Model.IPAddress"></div>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
<div class="dropdown-menu dropdown-menu-center z-30" aria-labelledby="avatar-popover-toggle">
|
||||
<has-permission entity="ClientIPAddress" required-permission="Read">
|
||||
<h6 class="dropdown-header font-weight-bold">@Model.IPAddress</h6>
|
||||
<div class="dropdown-divider"></div>
|
||||
</has-permission>
|
||||
|
||||
<div class="dropdown-item geo-country">@Model.GeoLocationInfo.Country</div>
|
||||
@if (!string.IsNullOrEmpty(Model.GeoLocationInfo.Region))
|
||||
{
|
||||
<div class="dropdown-item text-muted geo-region">@Model.GeoLocationInfo.Region</div>
|
||||
<div class="dropdown-divider"></div>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.GeoLocationInfo.Organization))
|
||||
{
|
||||
<div class="dropdown-item geo-organization">@Model.GeoLocationInfo.Organization</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- meta info block -->
|
||||
<div class="d-flex flex-column flex-md-row text-center text-md-left flex-wrap">
|
||||
<partial name="Meta/_Information.cshtml" model="@Model.Meta"/>
|
||||
</div>
|
||||
|
||||
<hr class="mt-10 mb-10"/>
|
||||
|
||||
<!-- meta filter list -->
|
||||
<div class="mb-10 mt-10">
|
||||
@foreach (var type in Enum.GetValues(typeof(MetaType)).Cast<MetaType>().Where(meta => !ignoredMetaTypes.Contains(meta)).OrderByDescending(meta => meta == MetaType.All))
|
||||
{
|
||||
var buttonClass = !Model.MetaFilterType.HasValue && type == MetaType.All || Model.MetaFilterType.HasValue && Model.MetaFilterType.Value.ToString() == type.ToString() ? "btn-primary text-light" : "text-muted";
|
||||
<a asp-action="Profile" asp-controller="Client"
|
||||
class="meta-filter no-decoration"
|
||||
asp-route-id="@Model.ClientId"
|
||||
asp-route-metaFilterType="@type"
|
||||
data-meta-type="@type">
|
||||
<button class="btn btn-sm d-none d-md-inline mt-5 mb-5 @buttonClass">@type.ToTranslatedName()</button>
|
||||
<button class="btn btn-block d-block d-md-none mt-10 mb-10 @buttonClass">@type.ToTranslatedName()</button>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (!ViewBag.Authorized && !ViewBag.EnablePrivilegedUserPrivacy || ViewBag.Authorized)
|
||||
{
|
||||
<div class="row d-md-flex pt-2">
|
||||
<div id="profile_events" class="text-muted text-left pl-md-0 pr-md-0">
|
||||
@await Component.InvokeAsync("ProfileMetaList", new { clientId = Model.ClientId, count = 30, offset = 0, startAt = DateTime.UtcNow, metaType = Model.MetaFilterType })
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<hr class="mt-10 mb-10"/>
|
||||
|
||||
<div class="text-center">
|
||||
<i id="loaderLoad" class="oi oi-chevron-bottom loader-load-more text-primary" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@if ((!ViewBag.Authorized && !ViewBag.EnablePrivilegedUserPrivacy) || ViewBag.Authorized)
|
||||
{
|
||||
<div class="row d-md-flex pt-2">
|
||||
<div id="profile_events" class="text-muted text-left pl-4 pr-4 pl-md-0 pr-md-0">
|
||||
@await Component.InvokeAsync("ProfileMetaList", new { clientId = Model.ClientId, count = 30, offset = 0, startAt = DateTime.UtcNow, metaType = Model.MetaFilterType })
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<!-- actions desktop -->
|
||||
@{
|
||||
var menuItems = new SideContextMenuItems
|
||||
{
|
||||
MenuTitle = "Actions",
|
||||
};
|
||||
|
||||
if (Model.Online)
|
||||
{
|
||||
menuItems.Items.Add(new SideContextMenuItem
|
||||
{
|
||||
Title = "Join Game",
|
||||
IsLink = true,
|
||||
IsButton = true,
|
||||
Reference = Model.ConnectProtocolUrl,
|
||||
Tooltip = $"Playing on {Model.CurrentServerName.StripColors()}",
|
||||
Icon = "oi-play-circle"
|
||||
});
|
||||
}
|
||||
|
||||
if (Model.LevelInt != -1 && ViewBag.Authorized)
|
||||
{
|
||||
menuItems.Items.Add(new SideContextMenuItem
|
||||
{
|
||||
Title = "Change Level",
|
||||
IsButton = true,
|
||||
Reference = "edit",
|
||||
Icon = "oi-cog",
|
||||
});
|
||||
}
|
||||
|
||||
menuItems.Items.Add(new SideContextMenuItem
|
||||
{
|
||||
Title = "View Stats",
|
||||
IsButton = true,
|
||||
IsLink = true,
|
||||
Reference = Url.Action("Advanced", "ClientStatistics", new { id = Model.ClientId }),
|
||||
Icon = "oi-graph",
|
||||
});
|
||||
|
||||
if (!isPermBanned && ViewBag.Authorized)
|
||||
{
|
||||
menuItems.Items.Add(new SideContextMenuItem
|
||||
{
|
||||
Title = isFlagged ? "Unflag" : "Flag",
|
||||
IsButton = true,
|
||||
Reference = isFlagged ? "unflag" : "flag",
|
||||
Icon = "oi-flag"
|
||||
});
|
||||
}
|
||||
|
||||
if ((Model.LevelInt < (int)ViewBag.User.Level && !Model.HasActivePenalty || isTempBanned) && ViewBag.Authorized)
|
||||
{
|
||||
menuItems.Items.Add(new SideContextMenuItem
|
||||
{
|
||||
Title = "Ban",
|
||||
IsButton = true,
|
||||
Reference = "ban",
|
||||
Icon = "oi-lock-unlocked",
|
||||
});
|
||||
}
|
||||
|
||||
if ((Model.LevelInt < (int)ViewBag.User.Level && Model.HasActivePenalty || isTempBanned) && ViewBag.Authorized)
|
||||
{
|
||||
menuItems.Items.Add(new SideContextMenuItem
|
||||
{
|
||||
Title = "Unban",
|
||||
IsButton = true,
|
||||
Reference = "unban",
|
||||
Icon = "oi-lock-locked",
|
||||
});
|
||||
}
|
||||
}
|
||||
<partial name="_SideContextMenu" for="@menuItems"></partial>
|
||||
|
||||
<div class="row">
|
||||
<div class="oi oi-chevron-bottom text-center mt-2 btn btn-primary btn-block loader-load-more" title="Load more meta" data-action="unban" aria-hidden="true"></div>
|
||||
</div>
|
||||
|
||||
@section targetid {
|
||||
|
@ -1,53 +1,60 @@
|
||||
@using SharedLibraryCore.Dtos.Meta.Responses
|
||||
@model AdministeredPenaltyResponse
|
||||
@{
|
||||
string localizationKey = $"WEBFRONT_CLIENT_META_PENALIZED_{Model.PenaltyType.ToString().ToUpper()}_V2";
|
||||
var localizationKey = $"WEBFRONT_CLIENT_META_PENALIZED_{Model.PenaltyType.ToString().ToUpper()}_V2";
|
||||
}
|
||||
|
||||
<div class="d-inline">
|
||||
@foreach (var match in Utilities.SplitTranslationTokens(localizationKey))
|
||||
<has-permission entity="Penalty" required-permission="Read">
|
||||
@if (TempData["ShowMetaHeader"] as bool? ?? false)
|
||||
{
|
||||
if (match.IsInterpolation)
|
||||
{
|
||||
if (match.MatchValue == "action")
|
||||
{
|
||||
<span class="penalties-color-@Model.PenaltyType.ToString().ToLower()">@match.TranslationValue</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "offender")
|
||||
{
|
||||
<span class="text-highlight">
|
||||
<a class="link-inverse" href="@Model.OffenderClientId">
|
||||
<color-code value="@Model.OffenderName"></color-code>
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "reason")
|
||||
{
|
||||
<span class="text-white">
|
||||
@if (ViewBag.Authorized && !string.IsNullOrEmpty(Model.AutomatedOffense) && Model.PenaltyType != Data.Models.EFPenalty.PenaltyType.Warning)
|
||||
{
|
||||
<span>@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.AutomatedOffense)</span>
|
||||
<span class="oi oi-list-rich align-top text-primary automated-penalty-info-detailed" data-penalty-id="@Model.PenaltyId" style="margin-top: 0.125rem;" title="@ViewBag.Localization["WEBFRONT_CLIENT_META_AC_METRIC"]"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@Model.Offense"></color-code>
|
||||
}
|
||||
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "time")
|
||||
{
|
||||
<span class="text-white">@Model.LengthText</span>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<span>@match.MatchValue</span>
|
||||
}
|
||||
<partial name="./_MetaHeader.cshtml" for="@Model.When"/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="d-inline">
|
||||
@foreach (var match in Utilities.SplitTranslationTokens(localizationKey))
|
||||
{
|
||||
if (match.IsInterpolation)
|
||||
{
|
||||
if (match.MatchValue == "action")
|
||||
{
|
||||
<span class="penalties-color-@Model.PenaltyType.ToString().ToLower()">@match.TranslationValue</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "offender")
|
||||
{
|
||||
<span class="text-highlight">
|
||||
<a class="link-inverse" href="@Model.OffenderClientId">
|
||||
<color-code value="@Model.OffenderName"></color-code>
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "reason")
|
||||
{
|
||||
<span class="text-light-dm text-dark-lm">
|
||||
@if (ViewBag.Authorized && !string.IsNullOrEmpty(Model.AutomatedOffense) && Model.PenaltyType != Data.Models.EFPenalty.PenaltyType.Warning)
|
||||
{
|
||||
<span>@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.AutomatedOffense)</span>
|
||||
<span class="oi oi-list-rich align-top text-primary automated-penalty-info-detailed" data-penalty-id="@Model.PenaltyId" style="margin-top: 0.125rem;" title="@ViewBag.Localization["WEBFRONT_CLIENT_META_AC_METRIC"]"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@Model.Offense"></color-code>
|
||||
}
|
||||
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "time")
|
||||
{
|
||||
<span class="text-light-dm text-dark-lm">@Model.LengthText</span>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<span>@match.MatchValue</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</has-permission>
|
||||
|
@ -4,6 +4,11 @@
|
||||
var localizationKey = $"WEBFRONT_CLIENT_META_CONNECTION_{Model.ConnectionType.ToString().ToUpper()}";
|
||||
}
|
||||
|
||||
@if (TempData["ShowMetaHeader"] as bool? ?? false)
|
||||
{
|
||||
<partial name="./_MetaHeader.cshtml" for="@Model.When"/>
|
||||
}
|
||||
|
||||
@foreach (var token in Utilities.SplitTranslationTokens(localizationKey))
|
||||
{
|
||||
if (token.IsInterpolation)
|
||||
@ -11,10 +16,10 @@
|
||||
switch (token.MatchValue)
|
||||
{
|
||||
case "action":
|
||||
<span class="@(Model.ConnectionType == Reference.ConnectionType.Connect ? "text-light-green" : "text-warning")">@token.TranslationValue</span>
|
||||
<span class="@(Model.ConnectionType == Reference.ConnectionType.Connect ? "text-light-green" : "text-secondary")">@token.TranslationValue</span>
|
||||
break;
|
||||
case "server":
|
||||
<span class="text-white">
|
||||
<span class="text-light-dm text-dark-lm">
|
||||
<color-code value="@Model.ServerName"></color-code>
|
||||
</span>
|
||||
break;
|
||||
|
@ -1,20 +1,20 @@
|
||||
@model IEnumerable<SharedLibraryCore.Dtos.Meta.Responses.InformationResponse>
|
||||
@{
|
||||
var informationMeta = Model
|
||||
.Where(_meta => _meta.Type == SharedLibraryCore.Interfaces.MetaType.Information)
|
||||
.OrderBy(_meta => _meta.Order)
|
||||
.GroupBy(_meta => _meta.Column)
|
||||
.OrderBy(_grouping => _grouping.Key);
|
||||
.Where(meta => meta.Type == SharedLibraryCore.Interfaces.MetaType.Information)
|
||||
.OrderBy(meta => meta.Order)
|
||||
.Select((meta, i) => new { index = i, meta })
|
||||
.GroupBy(meta => meta.index / 5);
|
||||
}
|
||||
|
||||
@foreach (var metaColumn in informationMeta)
|
||||
{
|
||||
<div class="text-center text-lg-left mr-0 mr-lg-4">
|
||||
<div class="mr-20">
|
||||
@foreach (var meta in metaColumn)
|
||||
{
|
||||
<div class="profile-meta-entry" title="@meta.ToolTipText">
|
||||
<div class="profile-meta-entry font-size-12" data-toggle="@(!string.IsNullOrEmpty(meta.meta.ToolTipText) ? "tooltip" : "")" data-title="@meta.meta.ToolTipText" data-placement="bottom">
|
||||
|
||||
@{var results = Utilities.SplitTranslationTokens(meta.Key);}
|
||||
@{var results = Utilities.SplitTranslationTokens(meta.meta.Key);}
|
||||
|
||||
@if (results.Any(_result => _result.IsInterpolation))
|
||||
{
|
||||
@ -22,7 +22,7 @@
|
||||
{
|
||||
if (result.IsInterpolation)
|
||||
{
|
||||
<span class="profile-meta-value text-primary"><color-code value="@meta.Value"></color-code></span>
|
||||
<span class="profile-meta-value text-primary"><color-code value="@meta.meta.Value"></color-code></span>
|
||||
}
|
||||
|
||||
else
|
||||
@ -34,8 +34,8 @@
|
||||
|
||||
else
|
||||
{
|
||||
<span class="profile-meta-value text-primary"><color-code value="@meta.Value"></color-code></span>
|
||||
<span class="profile-meta-title text-muted"> @meta.Key</span>
|
||||
<span class="profile-meta-value text-primary"><color-code value="@meta.meta.Value"></color-code></span>
|
||||
<span class="profile-meta-title text-muted">@meta.meta.Key</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
@ -1,17 +1,24 @@
|
||||
@using SharedLibraryCore.Dtos.Meta.Responses
|
||||
@model MessageResponse
|
||||
|
||||
@if (TempData["ShowMetaHeader"] as bool? ?? false)
|
||||
{
|
||||
<partial name="./_MetaHeader.cshtml" for="@Model.When"/>
|
||||
}
|
||||
|
||||
<span class="client-message" data-serverid="@Model.ServerId" data-when="@Model.When.ToFileTimeUtc()">
|
||||
<span class="oi oi-chevron-right text-white-50 align-middle client-message-prefix" title="@ViewBag.Localization["WEBFRONT_PROFILE_MESSAGE_CONTEXT"]" style="font-size: 0.75rem; margin-top: -0.256rem"></span>
|
||||
<span data-title="View Context" data-toggle="tooltip" data-placement="right">
|
||||
<span class="oi oi-chevron-right align-middle client-message-prefix" style="font-size: 0.75rem; margin-top: -0.256rem"></span>
|
||||
</span>
|
||||
<span class="text-muted @(Model.IsQuickMessage ? "font-weight-bold" : "")">
|
||||
@if (!Model.SentIngame)
|
||||
{
|
||||
<span>[<span class="text-primary">@ViewBag.Localization["WEBFRONT_PROFILE_MESSAGE_EXTERNAL"]</span>]</span>
|
||||
}
|
||||
|
||||
|
||||
@if (Model.IsHidden && !ViewBag.Authorized)
|
||||
{
|
||||
<color-code value="@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], Model.HiddenMessage)"></color-code>
|
||||
<color-code value="@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], Model.HiddenMessage)"></color-code>
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -0,0 +1,6 @@
|
||||
@model DateTime
|
||||
@{ Layout = null;}
|
||||
<div class="pt-5 text-light-dm text-dark-lm font-size-18 ">
|
||||
<span>@Model.HumanizeForCurrentCulture()</span>
|
||||
</div>
|
||||
<hr/>
|
@ -1,29 +1,35 @@
|
||||
@model SharedLibraryCore.Dtos.Meta.Responses.PermissionLevelChangedResponse
|
||||
|
||||
@foreach (var token in Utilities.SplitTranslationTokens("WEBFRONT_CLIENT_META_PERMISSION_CHANGED"))
|
||||
{
|
||||
if (token.IsInterpolation)
|
||||
<has-permission entity="ClientLevel" required-permission="Read">
|
||||
@if (TempData["ShowMetaHeader"] as bool? ?? false)
|
||||
{
|
||||
switch (token.MatchValue)
|
||||
<partial name="./_MetaHeader.cshtml" for="@Model.When"/>
|
||||
}
|
||||
@foreach (var token in Utilities.SplitTranslationTokens("WEBFRONT_CLIENT_META_PERMISSION_CHANGED"))
|
||||
{
|
||||
if (token.IsInterpolation)
|
||||
{
|
||||
case "permission":
|
||||
<span class="level-color-@((int)Model.CurrentPermissionLevel)">@Model.CurrentPermissionLevel.ToLocalizedLevelName()</span>
|
||||
break;
|
||||
case "originClient":
|
||||
<span class="text-highlight">
|
||||
<a class="link-inverse" href="@Model.ChangedById">
|
||||
<color-code value="@Model.ChangedByName"></color-code>
|
||||
</a>
|
||||
</span>
|
||||
break;
|
||||
case "type":
|
||||
<span class="text-white-50">@token.TranslationValue</span>
|
||||
break;
|
||||
switch (token.MatchValue)
|
||||
{
|
||||
case "permission":
|
||||
<span class="level-color-@((int)Model.CurrentPermissionLevel)">@Model.CurrentPermissionLevel.ToLocalizedLevelName()</span>
|
||||
break;
|
||||
case "originClient":
|
||||
<span class="text-highlight">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@Model.ChangedById">
|
||||
<color-code value="@Model.ChangedByName"></color-code>
|
||||
</a>
|
||||
</span>
|
||||
break;
|
||||
case "type":
|
||||
<span class="text-white-50">@token.TranslationValue</span>
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<span class="text-muted">@token.MatchValue</span>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<span class="text-muted">@token.MatchValue</span>
|
||||
}
|
||||
}
|
||||
</has-permission>
|
||||
|
@ -2,72 +2,79 @@
|
||||
@model ReceivedPenaltyResponse
|
||||
|
||||
@{
|
||||
string localizationKey = $"WEBFRONT_CLIENT_META_WAS_PENALIZED_{Model.PenaltyType.ToString().ToUpper()}_V2";
|
||||
var localizationKey = $"WEBFRONT_CLIENT_META_WAS_PENALIZED_{Model.PenaltyType.ToString().ToUpper()}_V2";
|
||||
}
|
||||
|
||||
<div class="d-inline">
|
||||
@foreach (var match in Utilities.SplitTranslationTokens(localizationKey))
|
||||
<has-permission entity="ClientLevel" required-permission="Read">
|
||||
@if (TempData["ShowMetaHeader"] as bool? ?? false)
|
||||
{
|
||||
if (match.IsInterpolation)
|
||||
{
|
||||
if (match.MatchValue == "action")
|
||||
{
|
||||
<span class="penalties-color-@Model.PenaltyType.ToString().ToLower()">@match.TranslationValue</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "punisher")
|
||||
{
|
||||
<span class="text-highlight">
|
||||
<a class="link-inverse" href="@Model.PunisherClientId">
|
||||
<color-code value="@Model.PunisherName"></color-code>
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "reason")
|
||||
{
|
||||
<span class="text-white">
|
||||
@if (ViewBag.Authorized && !string.IsNullOrEmpty(Model.AutomatedOffense) && Model.PenaltyType != Data.Models.EFPenalty.PenaltyType.Warning && Model.PenaltyType != Data.Models.EFPenalty.PenaltyType.Kick)
|
||||
{
|
||||
<span>@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.AutomatedOffense)</span>
|
||||
<span class="oi oi-list-rich align-top text-primary automated-penalty-info-detailed" data-penalty-id="@Model.PenaltyId" style="margin-top: 0.125rem;" title="@ViewBag.Localization["WEBFRONT_CLIENT_META_AC_METRIC"]"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@Model.Offense"></color-code>
|
||||
}
|
||||
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "time")
|
||||
{
|
||||
<span class="text-white">@Model.LengthText</span>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<span>@match.MatchValue</span>
|
||||
}
|
||||
<partial name="./_MetaHeader.cshtml" for="@Model.When"/>
|
||||
}
|
||||
|
||||
@if (Model.ClientId != Model.OffenderClientId)
|
||||
{
|
||||
<span>—</span>
|
||||
@foreach (var helperResult in Utilities.SplitTranslationTokens("WEBFRONT_PROFILE_LINKED_ACCOUNT"))
|
||||
<div class="d-inline">
|
||||
@foreach (var match in Utilities.SplitTranslationTokens(localizationKey))
|
||||
{
|
||||
if (!helperResult.IsInterpolation)
|
||||
if (match.IsInterpolation)
|
||||
{
|
||||
<span>@helperResult.MatchValue</span>
|
||||
if (match.MatchValue == "action")
|
||||
{
|
||||
<span class="penalties-color-@Model.PenaltyType.ToString().ToLower()">@match.TranslationValue</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "punisher")
|
||||
{
|
||||
<span class="text-highlight">
|
||||
<a class="link-inverse" href="@Model.PunisherClientId">
|
||||
<color-code value="@Model.PunisherName"></color-code>
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "reason")
|
||||
{
|
||||
<span class="text-light-dm text-dark-lm">
|
||||
@if (ViewBag.Authorized && !string.IsNullOrEmpty(Model.AutomatedOffense) && Model.PenaltyType != Data.Models.EFPenalty.PenaltyType.Warning && Model.PenaltyType != Data.Models.EFPenalty.PenaltyType.Kick)
|
||||
{
|
||||
<span>@Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.AutomatedOffense)</span>
|
||||
<span class="oi oi-list-rich align-top text-primary automated-penalty-info-detailed" data-penalty-id="@Model.PenaltyId" style="margin-top: 0.125rem;" title="@ViewBag.Localization["WEBFRONT_CLIENT_META_AC_METRIC"]"></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<color-code value="@Model.Offense"></color-code>
|
||||
}
|
||||
|
||||
</span>
|
||||
}
|
||||
|
||||
else if (match.MatchValue == "time")
|
||||
{
|
||||
<span class="text-light-dm text-dark-lm">@Model.LengthText</span>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<a class="link-inverse" href="@Model.OffenderClientId">
|
||||
<color-code value="@Model.OffenderName"></color-code>
|
||||
</a>
|
||||
<span>@match.MatchValue</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (Model.ClientId != Model.OffenderClientId)
|
||||
{
|
||||
<span>—</span>
|
||||
@foreach (var helperResult in Utilities.SplitTranslationTokens("WEBFRONT_PROFILE_LINKED_ACCOUNT"))
|
||||
{
|
||||
if (!helperResult.IsInterpolation)
|
||||
{
|
||||
<span>@helperResult.MatchValue</span>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<a class="link-inverse" href="@Model.OffenderClientId">
|
||||
<color-code value="@Model.OffenderName"></color-code>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</has-permission>
|
||||
|
@ -1,6 +1,11 @@
|
||||
@using SharedLibraryCore.Dtos.Meta.Responses
|
||||
@model UpdatedAliasResponse
|
||||
|
||||
@if (TempData["ShowMetaHeader"] as bool? ?? false)
|
||||
{
|
||||
<partial name="./_MetaHeader.cshtml" for="@Model.When"/>
|
||||
}
|
||||
|
||||
@foreach (var token in Utilities.SplitTranslationTokens("WEBFRONT_PROFILE_META_CONNECT_ALIAS"))
|
||||
{
|
||||
if (token.IsInterpolation)
|
||||
@ -8,12 +13,14 @@
|
||||
switch (token.MatchValue)
|
||||
{
|
||||
case "action":
|
||||
<span class="text-warning">@token.TranslationValue</span>
|
||||
<span class="text-secondary">@token.TranslationValue</span>
|
||||
break;
|
||||
case "alias":
|
||||
<span class="text-white">
|
||||
<span class="text-light-dm text-dark-lm">
|
||||
<color-code value="@Model.Name"></color-code>
|
||||
[@Model.IPAddress]
|
||||
<has-permission entity="ClientIPAddress" required-permission="Read">
|
||||
[@Model.IPAddress]
|
||||
</has-permission>
|
||||
</span>
|
||||
break;
|
||||
}
|
||||
|
@ -6,26 +6,21 @@
|
||||
@using Humanizer
|
||||
@using Humanizer.Localisation
|
||||
@using IW4MAdmin.Plugins.Stats
|
||||
@using WebfrontCore.ViewModels
|
||||
@model Stats.Dtos.AdvancedStatsInfo
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Advanced Client Statistics";
|
||||
ViewBag.Description = Model.ClientName.StripColors();
|
||||
|
||||
const int maxItems = 5;
|
||||
const string headshotKey = "MOD_HEAD_SHOT";
|
||||
const string headshotKey2 = "headshot";
|
||||
const string meleeKey = "MOD_MELEE";
|
||||
|
||||
var suicideKeys = new[] {"MOD_SUICIDE", "MOD_FALLING"};
|
||||
var suicideKeys = new[] { "MOD_SUICIDE", "MOD_FALLING" };
|
||||
// if they've not copied default settings config this could be null
|
||||
var config = (GameStringConfiguration) ViewBag.Config ?? new GameStringConfiguration();
|
||||
var config = (GameStringConfiguration)ViewBag.Config ?? new GameStringConfiguration();
|
||||
|
||||
var headerClass = Model.Level == EFClient.Permission.Banned ? "bg-danger" : "bg-primary";
|
||||
var textClass = Model.Level == EFClient.Permission.Banned ? "text-danger" : "text-primary";
|
||||
var borderBottomClass = Model.Level == EFClient.Permission.Banned ? "border-bottom-danger border-top-danger" : "border-bottom border-top";
|
||||
var borderClass = Model.Level == EFClient.Permission.Banned ? "border-danger" : "border-primary";
|
||||
var buttonClass = Model.Level == EFClient.Permission.Banned ? "btn-danger" : "btn-primary";
|
||||
|
||||
string GetWeaponNameForHit(EFClientHitStatistic stat)
|
||||
{
|
||||
if (stat == null)
|
||||
@ -46,7 +41,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
var attachmentText = string.Join('+', new[]
|
||||
var attachmentText = string.Join(" + ", new[]
|
||||
{
|
||||
config.GetStringForGame(attachment.Attachment1.Name, attachment.Attachment1.Game),
|
||||
config.GetStringForGame(attachment.Attachment2?.Name, attachment.Attachment2?.Game),
|
||||
@ -58,11 +53,11 @@
|
||||
|
||||
var weapons = Model.ByWeapon
|
||||
.Where(hit => hit.DamageInflicted > 0 || (hit.DamageInflicted == 0 && hit.HitCount > 0))
|
||||
.GroupBy(hit => new {hit.WeaponId})
|
||||
.GroupBy(hit => new { hit.WeaponId })
|
||||
.Select(group =>
|
||||
{
|
||||
var withoutAttachments = group.FirstOrDefault(hit => hit.WeaponAttachmentComboId == null);
|
||||
var mostUsedAttachment = group.Except(new[] {withoutAttachments})
|
||||
var mostUsedAttachment = group.Except(new[] { withoutAttachments })
|
||||
.OrderByDescending(g => g.DamageInflicted)
|
||||
.GroupBy(g => g.WeaponAttachmentComboId)
|
||||
.FirstOrDefault()
|
||||
@ -72,7 +67,7 @@
|
||||
{
|
||||
return withoutAttachments;
|
||||
}
|
||||
|
||||
|
||||
withoutAttachments.WeaponAttachmentComboId = mostUsedAttachment.WeaponAttachmentComboId;
|
||||
withoutAttachments.WeaponAttachmentCombo = mostUsedAttachment.WeaponAttachmentCombo;
|
||||
|
||||
@ -107,15 +102,15 @@
|
||||
.Where(weapon => weapon.DamageInflicted > 0)
|
||||
.GroupBy(weapon => weapon.WeaponId)
|
||||
.Count()
|
||||
: (int?) null; // want to default to -- in ui instead of 0
|
||||
: (int?)null; // want to default to -- in ui instead of 0
|
||||
|
||||
var activeTime = weapons.Any()
|
||||
? TimeSpan.FromSeconds(weapons.Sum(weapon => weapon.UsageSeconds ?? 0))
|
||||
: (TimeSpan?) null; // want to default to -- in ui instead of 0
|
||||
: (TimeSpan?)null; // want to default to -- in ui instead of 0
|
||||
|
||||
var kdr = aggregate == null
|
||||
? null
|
||||
: Math.Round(aggregate.KillCount / (float) aggregate.DeathCount, 2).ToString(Utilities.CurrentLocalization.Culture);
|
||||
: Math.Round(aggregate.KillCount / (float)aggregate.DeathCount, 2).ToString(Utilities.CurrentLocalization.Culture);
|
||||
|
||||
var serverLegacyStat = Model.LegacyStats
|
||||
.FirstOrDefault(stat => stat.ServerId == Model.ServerId);
|
||||
@ -140,15 +135,15 @@
|
||||
|
||||
var headShots = allPerServer.Any()
|
||||
? allPerServer.Where(hit => hit.MeansOfDeath?.Name == headshotKey || hit.HitLocation?.Name == headshotKey2).Sum(hit => hit.HitCount)
|
||||
: (int?) null; // want to default to -- in ui instead of 0
|
||||
: (int?)null; // want to default to -- in ui instead of 0
|
||||
|
||||
var meleeKills = allPerServer.Any()
|
||||
? allPerServer.Where(hit => hit.MeansOfDeath?.Name == meleeKey).Sum(hit => hit.KillCount)
|
||||
: (int?) null;
|
||||
: (int?)null;
|
||||
|
||||
var suicides = allPerServer.Any()
|
||||
? allPerServer.Where(hit => suicideKeys.Contains(hit.MeansOfDeath?.Name ?? "")).Sum(hit => hit.KillCount)
|
||||
: (int?) null;
|
||||
: (int?)null;
|
||||
|
||||
var statCards = new[]
|
||||
{
|
||||
@ -172,7 +167,7 @@
|
||||
Name = (ViewBag.Localization["WEBFRONT_ADV_STATS_SCORE"] as string).Titleize(),
|
||||
Value = score.ToNumericalString()
|
||||
},
|
||||
new
|
||||
new
|
||||
{
|
||||
Name = (ViewBag.Localization["WEBFRONT_ADV_STATS_ZSCORE"] as string),
|
||||
Value = Model.ZScore.ToNumericalString(2)
|
||||
@ -235,205 +230,170 @@
|
||||
};
|
||||
}
|
||||
|
||||
<div class="w-100 @headerClass mb-1">
|
||||
<select class="w-100 @headerClass text-white pl-4 pr-4 pt-2 pb-2 m-auto h5 @borderClass"
|
||||
id="server_selector"
|
||||
onchange="if (this.value) window.location.href=this.value">
|
||||
@if (Model.ServerId == null)
|
||||
{
|
||||
<option value="@Url.Action("Advanced", "ClientStatistics")" selected>@ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"]</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@Url.Action("Advanced", "ClientStatistics")">@ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"]</option>
|
||||
}
|
||||
@foreach (var server in Model.Servers)
|
||||
{
|
||||
if (server.Endpoint == Model.ServerEndpoint)
|
||||
{
|
||||
<option value="@Url.Action("Advanced", "ClientStatistics", new {serverId = server.Endpoint})" selected>@server.Name.StripColors()</option>
|
||||
}
|
||||
else
|
||||
{
|
||||
<option value="@Url.Action("Advanced", "ClientStatistics", new {serverId = server.Endpoint})">@server.Name.StripColors()</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="@headerClass p-4 mb-0 d-flex flex-wrap">
|
||||
<div class="content row mt-20">
|
||||
<!-- main content -->
|
||||
<div class="col-12 col-lg-9 col-xl-10 mt-0">
|
||||
<h2 class="content-title mb-0">Player Stats</h2>
|
||||
<span class="text-muted">
|
||||
<color-code value="@(Model.Servers.FirstOrDefault(server => server.Endpoint == Model.ServerEndpoint)?.Name ?? ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"])"></color-code>
|
||||
</span>
|
||||
|
||||
<div class="align-self-center d-flex flex-column flex-lg-row text-center text-lg-left mb-3 mb-md-0 p-2 ml-lg-0 mr-lg-0 ml-auto mr-auto">
|
||||
<div class="mr-lg-3 m-auto">
|
||||
<img class="img-fluid align-self-center" id="rank_icon" src="~/images/stats/ranks/rank_@(Model.ZScore.RankIconIndexForZScore()).png" alt="@performance"/>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-self-center" id="client_stats_summary">
|
||||
<div class="h1 mb-0 font-weight-bold">
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@Model.ClientId">@Model.ClientName.StripColors()</a>
|
||||
<!-- top card -->
|
||||
<div class="card p-20 m-0 mt-15 mb-15">
|
||||
<div class="align-self-center d-flex flex-column flex-lg-row flex-fill mb-15">
|
||||
<!-- rank icon -->
|
||||
<img class="img-fluid align-self-center w-75" id="rank_icon" src="~/images/stats/ranks/rank_@(Model.ZScore.RankIconIndexForZScore()).png" alt="@performance"/>
|
||||
<!-- summary -->
|
||||
<div class="d-flex flex-column align-self-center m-10 text-center text-lg-left" id="client_stats_summary">
|
||||
<div class="font-size-20 mb-0 font-weight-bold">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@Model.ClientId" class="no-decoration">@Model.ClientName.StripColors()</a>
|
||||
</div>
|
||||
@if (Model.Level == EFClient.Permission.Banned)
|
||||
{
|
||||
<div class="h5 mb-0 text-danger">@ViewBag.Localization["GLOBAL_PERMISSION_BANNED"]</div>
|
||||
}
|
||||
else if (Model.ZScore != null)
|
||||
{
|
||||
if (Model.Ranking > 0)
|
||||
{
|
||||
<div class="h5 mb-0">@Html.Raw((ViewBag.Localization["WEBFRONT_ADV_STATS_RANKED"] as string).FormatExt(Model.Ranking))</div>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<div class="h5 mb-0">@ViewBag.Localization["WEBFRONT_ADV_STATS_EXPIRED"]</div>
|
||||
}
|
||||
if (Model.ServerId != null)
|
||||
{
|
||||
<div class="h5 mb-0">@Html.Raw((ViewBag.Localization["WEBFRONT_ADV_STATS_PERFORMANCE"] as string).FormatExt($"<span class=\"text-primary\">{performance.ToNumericalString()}</span>"))</div>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<div class="h5 mb-0">@Html.Raw((ViewBag.Localization["WEBFRONT_ADV_STATS_RATING"] as string).FormatExt($"<span class=\"text-primary\">{Model.Rating.ToNumericalString()}</span>"))</div>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<div class="h5 mb-0">@ViewBag.Localization["WEBFRONT_STATS_INDEX_UNRANKED"]</div>
|
||||
}
|
||||
</div>
|
||||
<!-- history graph -->
|
||||
@if (performanceHistory.Count() > 5)
|
||||
{
|
||||
<div class="w-half m-auto ml-lg-auto " id="client_performance_history_container">
|
||||
<canvas id="client_performance_history" data-history="@Html.Raw(Json.Serialize(performanceHistory))"></canvas>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (Model.Level == EFClient.Permission.Banned)
|
||||
{
|
||||
<div class="h5 mb-0">@ViewBag.Localization["GLOBAL_PERMISSION_BANNED"]</div>
|
||||
}
|
||||
else if (Model.ZScore != null)
|
||||
{
|
||||
if (Model.ServerId != null)
|
||||
<hr class="m-10"/>
|
||||
<div class="d-flex flex-row flex-wrap rounded">
|
||||
@foreach (var card in statCards)
|
||||
{
|
||||
<div class="h5 mb-0">@((ViewBag.Localization["WEBFRONT_ADV_STATS_PERFORMANCE"] as string).FormatExt(performance.ToNumericalString()))</div>
|
||||
<div class="stat-card bg-very-dark-dm bg-light-ex-lm p-15 m-md-5 w-half w-md-200 rounded flex-fill">
|
||||
@if (string.IsNullOrWhiteSpace(card.Value))
|
||||
{
|
||||
<div class="m-0">—</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="m-0 font-size-16 text-primary">@card.Value</div>
|
||||
}
|
||||
<div class="font-size-12 text-muted">@card.Name</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<div class="h5 mb-0">@((ViewBag.Localization["WEBFRONT_ADV_STATS_RATING"] as string).FormatExt(Model.Rating.ToNumericalString()))</div>
|
||||
}
|
||||
|
||||
if (Model.Ranking > 0)
|
||||
{
|
||||
<div class="h5 mb-0">@((ViewBag.Localization["WEBFRONT_ADV_STATS_RANKED"] as string).FormatExt(Model.Ranking.ToNumericalString()))</div>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<div class="h5 mb-0">@ViewBag.Localization["WEBFRONT_ADV_STATS_EXPIRED"]</div>
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<div class="h5 mb-0">@ViewBag.Localization["WEBFRONT_STATS_INDEX_UNRANKED"]</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-50 m-auto ml-md-auto mr-md-0" id="client_performance_history_container">
|
||||
<canvas id="client_performance_history" data-history="@Html.Raw(Json.Serialize(performanceHistory))"></canvas>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mb-4 bg-dark @borderBottomClass d-flex flex-wrap">
|
||||
@foreach (var card in statCards)
|
||||
{
|
||||
<div class="pl-3 pr-4 pb-3 pt-3 stat-card flex-fill w-50 w-md-auto">
|
||||
@if (string.IsNullOrWhiteSpace(card.Value))
|
||||
{
|
||||
<h5 class="card-title @textClass">—</h5>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h5 class="card-title @textClass">@card.Value</h5>
|
||||
}
|
||||
<h6 class="card-subtitle mb-0 text-muted">@card.Name</h6>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- WEAPONS USED -->
|
||||
<div class="col-12 mb-4">
|
||||
<div class="@headerClass h4 mb-1 p-2">
|
||||
<div class="text-center">@ViewBag.Localization["WEBFRONT_ADV_STATS_WEAP_USAGE"]</div>
|
||||
</div>
|
||||
<table class="table mb-0">
|
||||
<tr class="@headerClass">
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_WEAPON"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_FAV_ATTACHMENTS"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_KILLS"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_HITS"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_DAMAGE"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_USAGE"]</th>
|
||||
</tr>
|
||||
@foreach (var weaponHit in weapons.Take(maxItems))
|
||||
{
|
||||
<tr class="bg-dark">
|
||||
<td class="@textClass text-force-break">@GetWeaponNameForHit(weaponHit)</td>
|
||||
@{ var attachments = GetWeaponAttachmentName(weaponHit.WeaponAttachmentCombo); }
|
||||
@if (string.IsNullOrWhiteSpace(attachments))
|
||||
{
|
||||
<td class="text-muted text-force-break">—</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td class="text-muted text-force-break">@attachments</td>
|
||||
}
|
||||
<td class="text-success text-force-break">@weaponHit.KillCount.ToNumericalString()</td>
|
||||
<td class="text-muted text-force-break">@weaponHit.HitCount.ToNumericalString()</td>
|
||||
<td class="text-muted text-force-break">@weaponHit.DamageInflicted.ToNumericalString()</td>
|
||||
<td class="text-muted text-force-break">@TimeSpan.FromSeconds(weaponHit.UsageSeconds ?? 0).HumanizeForCurrentCulture(minUnit: TimeUnit.Second)</td>
|
||||
</tr>
|
||||
}
|
||||
<!-- OVERFLOW -->
|
||||
@foreach (var weaponHit in weapons.Skip(maxItems))
|
||||
{
|
||||
<tr class="bg-dark hidden-row" style="display:none">
|
||||
<td class="@textClass text-force-break">@GetWeaponNameForHit(weaponHit)</td>
|
||||
@{ var attachments = GetWeaponAttachmentName(weaponHit.WeaponAttachmentCombo); }
|
||||
@if (string.IsNullOrWhiteSpace(attachments))
|
||||
{
|
||||
<td class="text-muted text-force-break">—</td>
|
||||
}
|
||||
else
|
||||
{
|
||||
<td class="text-muted text-force-break">@attachments</td>
|
||||
}
|
||||
<td class="text-success text-force-break">@weaponHit.KillCount.ToNumericalString()</td>
|
||||
<td class="text-muted text-force-break">@weaponHit.HitCount.ToNumericalString()</td>
|
||||
<td class="text-muted text-force-break">@weaponHit.DamageInflicted.ToNumericalString()</td>
|
||||
<td class="text-muted text-force-break">@TimeSpan.FromSeconds(weaponHit.UsageSeconds ?? 0).HumanizeForCurrentCulture()</td>
|
||||
</tr>
|
||||
}
|
||||
<tr>
|
||||
</table>
|
||||
<button class="btn @buttonClass btn-block table-slide">
|
||||
<span class="oi oi-chevron-bottom"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- HIT LOCATIONS -->
|
||||
<div class="col-lg-6 col-12 pr-3 pr-lg-0" id="hit_location_table">
|
||||
<div class="@headerClass h4 mb-1 p-2">
|
||||
<div class="text-center">@ViewBag.Localization["WEBFRONT_ADV_STATS_HIT_LOCATIONS"]</div>
|
||||
</div>
|
||||
<table class="table @borderBottomClass bg-dark mb-0 pb-0">
|
||||
<tr class="@headerClass">
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_LOCATION"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_HITS"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_PERCENTAGE"]</th>
|
||||
<th class="text-force-break">@ViewBag.Localization["WEBFRONT_ADV_STATS_DAMAGE"]</th>
|
||||
</tr>
|
||||
<div class="d-flex flex-wrap flex-column-reverse flex-xl-row">
|
||||
<!-- hit locations -->
|
||||
@{
|
||||
var totalHits = filteredHitLocations.Sum(hit => hit.HitCount);
|
||||
}
|
||||
@foreach (var hitLocation in filteredHitLocations.Take(8))
|
||||
{
|
||||
<tr>
|
||||
<td class="@textClass text-force-break">@config.GetStringForGame(hitLocation.HitLocation.Name, hitLocation.HitLocation.Game)</td>
|
||||
<td class="text-success text-force-break">@hitLocation.HitCount</td>
|
||||
<td class="text-muted text-force-break">@Math.Round((hitLocation.HitCount / (float) totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)%</td>
|
||||
<td class="text-muted text-force-break">@hitLocation.DamageInflicted.ToNumericalString()</td>
|
||||
</tr>
|
||||
|
||||
var hitLocationsTable = new TableInfo(5)
|
||||
{
|
||||
Header = ViewBag.Localization["WEBFRONT_ADV_STATS_HIT_LOCATIONS"]
|
||||
};
|
||||
|
||||
hitLocationsTable.WithColumns(new string[]
|
||||
{
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_LOCATION"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_HITS"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_PERCENTAGE"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_DAMAGE"],
|
||||
}).WithRows(filteredHitLocations, hitLocation => new[]
|
||||
{
|
||||
config.GetStringForGame(hitLocation.HitLocation.Name, hitLocation.HitLocation.Game),
|
||||
hitLocation.HitCount.ToString(),
|
||||
$"{Math.Round((hitLocation.HitCount / (float)totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)}%",
|
||||
hitLocation.DamageInflicted.ToNumericalString()
|
||||
});
|
||||
}
|
||||
|
||||
@foreach (var hitLocation in filteredHitLocations.Skip(8))
|
||||
{
|
||||
<tr class="bg-dark hidden-row" style="display:none;">
|
||||
<td class="@textClass text-force-break">@config.GetStringForGame(hitLocation.HitLocation.Name, hitLocation.HitLocation.Game)</td>
|
||||
<td class="text-success text-force-break">@hitLocation.HitCount</td>
|
||||
<td class="text-muted text-force-break">@Math.Round((hitLocation.HitCount / (float) totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)%</td>
|
||||
<td class="text-muted text-force-break">@hitLocation.DamageInflicted.ToNumericalString()</td>
|
||||
</tr>
|
||||
<div class="mr-0 mr-xl-20 flex-fill flex-xl-grow-1">
|
||||
<partial name="_DataTable" for="@hitLocationsTable"></partial>
|
||||
|
||||
<div class="h-250 p-15 card m-0 d-flex justify-content-center rounded-bottom" id="hitlocation_container">
|
||||
<canvas id="hitlocation_model">
|
||||
</canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- weapons used -->
|
||||
@{
|
||||
var weaponsUsedTable = new TableInfo(10)
|
||||
{
|
||||
Header = ViewBag.Localization["WEBFRONT_ADV_STATS_WEAP_USAGE"]
|
||||
};
|
||||
|
||||
weaponsUsedTable.WithColumns(new string[]
|
||||
{
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_WEAPON"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_FAV_ATTACHMENTS"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_KILLS"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_HITS"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_DAMAGE"],
|
||||
ViewBag.Localization["WEBFRONT_ADV_STATS_USAGE"]
|
||||
}).WithRows(weapons, weapon => new[]
|
||||
{
|
||||
GetWeaponNameForHit(weapon),
|
||||
GetWeaponAttachmentName(weapon.WeaponAttachmentCombo) ?? "--",
|
||||
weapon.KillCount.ToNumericalString(),
|
||||
weapon.HitCount.ToNumericalString(),
|
||||
weapon.DamageInflicted.ToNumericalString(),
|
||||
TimeSpan.FromSeconds(weapon.UsageSeconds ?? 0).HumanizeForCurrentCulture(minUnit: TimeUnit.Second)
|
||||
});
|
||||
}
|
||||
</table>
|
||||
<button class="btn @buttonClass btn-block table-slide">
|
||||
<span class="oi oi-chevron-bottom"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-lg-6 col-12 pl-3 pl-lg-0">
|
||||
<div class="@borderBottomClass text-center h-100" id="hitlocation_container">
|
||||
<canvas id="hitlocation_model">
|
||||
</canvas>
|
||||
|
||||
<div class="flex-fill flex-xl-grow-1">
|
||||
<partial name="_DataTable" for="@weaponsUsedTable"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- side context menu -->
|
||||
@{
|
||||
var menuItems = new SideContextMenuItems
|
||||
{
|
||||
MenuTitle = "Game", Items = Model.Servers.Select(server => new SideContextMenuItem
|
||||
{
|
||||
IsLink = true,
|
||||
Reference = Url.Action("Advanced", "ClientStatistics", new { serverId = server.Endpoint }),
|
||||
Title = server.Name.StripColors(),
|
||||
IsActive = Model.ServerEndpoint == server.Endpoint
|
||||
}).Prepend(new SideContextMenuItem
|
||||
{
|
||||
IsLink = true,
|
||||
Reference = Url.Action("Advanced", "ClientStatistics"),
|
||||
Title = ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"],
|
||||
IsActive = Model.ServerEndpoint is null
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
<partial name="_SideContextMenu" for="@menuItems"></partial>
|
||||
</div>
|
||||
|
||||
|
||||
@{
|
||||
var projection = filteredHitLocations.Select(loc => new
|
||||
{
|
||||
@ -441,7 +401,7 @@
|
||||
// we want to count head and neck as the same
|
||||
percentage = (loc.HitLocation.Name == "head"
|
||||
? filteredHitLocations.FirstOrDefault(c => c.HitLocation.Name == "neck")?.HitCount ?? 0 + loc.HitCount
|
||||
: loc.HitCount) / (float) totalHits
|
||||
: loc.HitCount) / (float)totalHits
|
||||
}).ToList();
|
||||
var maxPercentage = projection.Any() ? projection.Max(p => p.percentage) : 0;
|
||||
}
|
||||
@ -456,4 +416,4 @@
|
||||
<environment include="Development">
|
||||
<script type="text/javascript" src="~/js/advanced_stats.js"></script>
|
||||
</environment>
|
||||
}
|
||||
}
|
||||
|
@ -3,149 +3,90 @@
|
||||
@{
|
||||
Layout = null;
|
||||
var loc = Utilities.CurrentLocalization.LocalizationIndex.Set;
|
||||
double getDeviation(double deviations) => Math.Pow(Math.E, 5.259 + (deviations * 0.812));
|
||||
string rankIcon(double? elo)
|
||||
{
|
||||
if (elo >= getDeviation(-0.75) && elo < getDeviation(1.25))
|
||||
{
|
||||
return "0_no-place/menu_div_no_place.png";
|
||||
}
|
||||
if (elo >= getDeviation(0.125) && elo < getDeviation(0.625))
|
||||
{
|
||||
return "1_iron/menu_div_iron_sub03.png";
|
||||
}
|
||||
if (elo >= getDeviation(0.625) && elo < getDeviation(1.0))
|
||||
{
|
||||
return "2_bronze/menu_div_bronze_sub03.png";
|
||||
}
|
||||
if (elo >= getDeviation(1.0) && elo < getDeviation(1.25))
|
||||
{
|
||||
return "3_silver/menu_div_silver_sub03.png";
|
||||
}
|
||||
if (elo >= getDeviation(1.25) && elo < getDeviation(1.5))
|
||||
{
|
||||
return "4_gold/menu_div_gold_sub03.png";
|
||||
}
|
||||
if (elo >= getDeviation(1.5) && elo < getDeviation(1.75))
|
||||
{
|
||||
return "5_platinum/menu_div_platinum_sub03.png";
|
||||
}
|
||||
if (elo >= getDeviation(1.75) && elo < getDeviation(2.0))
|
||||
{
|
||||
return "6_semipro/menu_div_semipro_sub03.png";
|
||||
}
|
||||
if (elo >= getDeviation(2.0))
|
||||
{
|
||||
return "7_pro/menu_div_pro_sub03.png";
|
||||
}
|
||||
|
||||
return "0_no-place/menu_div_no_place.png";
|
||||
}
|
||||
}
|
||||
|
||||
@if (Model.Count == 0)
|
||||
{
|
||||
<div class="p-2 text-center">@Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_NOQUALIFY"]</div>
|
||||
<div class="card m-0 mt-15">
|
||||
<div class="d-flex">
|
||||
<i class="oi oi-timer align-self-center mb-10" style="font-size: 6rem;"></i>
|
||||
<div class="p-15">
|
||||
<h2 class="content-title mb-0">@Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_NOQUALIFY"]</h2>
|
||||
<span class="text-muted">Check back after some more time has passed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@foreach (var stat in Model)
|
||||
{
|
||||
<div class="row ml-0 mr-0 pt-2 pb-2">
|
||||
@if (ViewBag.UseNewStats)
|
||||
{
|
||||
<img class="align-self-center d-block d-md-none m-auto pb-3 pt-3" src="~/images/stats/ranks/rank_@(stat.ZScore.RankIconIndexForZScore()).png" alt="@stat.Performance"/>
|
||||
}
|
||||
<div class="col-md-4 text-md-left text-center">
|
||||
<div class="h2 d-flex flex-row justify-content-center justify-content-md-start align-items-center">
|
||||
<div class="text-muted">#@stat.Ranking</div>
|
||||
@if (stat.RatingChange > 0)
|
||||
{
|
||||
<div class="d-flex flex-column text-center pl-1">
|
||||
<div class="oi oi-caret-top text-success client-rating-change-up"></div>
|
||||
<div class="client-rating-change-amount text-success">@stat.RatingChange</div>
|
||||
<div class="card m-0 mt-15 p-20 d-flex flex-column flex-md-row justify-content-between">
|
||||
<div class="d-flex flex-column w-full w-md-quarter">
|
||||
<div class="d-flex align-items-center mb-15">
|
||||
<div class="d-flex text-muted">
|
||||
<span class="font-size-20">#</span>
|
||||
<div style="font-size: 4.5rem; line-height: 4.5rem;font-family: SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;">@stat.Ranking</div>
|
||||
</div>
|
||||
<div class="ml-10">
|
||||
<div class="d-flex flex-row">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@stat.ClientId" class="no-decoration text-light-dm text-dark-lm font-size-20 text-force-break" style="line-height: 2.5rem;">
|
||||
<color-code value="@stat.Name" allow="@ViewBag.EnableColorCodes"></color-code>
|
||||
</a>
|
||||
@if (stat.RatingChange > 0)
|
||||
{
|
||||
<div class="d-flex flex-column text-center ml-5 mr-5 align-self-center">
|
||||
<div class="oi oi-caret-top text-success client-rating-change-up"></div>
|
||||
<div class="client-rating-change-amount text-success">@stat.RatingChange</div>
|
||||
</div>
|
||||
}
|
||||
@if (stat.RatingChange < 0)
|
||||
{
|
||||
<div class="d-flex flex-column text-center ml-5 mr-5 align-self-center">
|
||||
<div class="client-rating-change-amount client-rating-change-amount-down text-danger">@Math.Abs(stat.RatingChange)</div>
|
||||
<div class="oi oi-caret-bottom text-danger client-rating-change-down"></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (stat.RatingChange < 0)
|
||||
{
|
||||
<div class="d-flex flex-column text-center pl-1">
|
||||
<div class="client-rating-change-amount client-rating-change-amount-down text-danger">@Math.Abs(stat.RatingChange)</div>
|
||||
<div class="oi oi-caret-bottom text-danger client-rating-change-down"></div>
|
||||
</div>
|
||||
}
|
||||
<span class="text-muted pr-1 pl-1">–</span>
|
||||
@if (!ViewBag.UseNewStats)
|
||||
{
|
||||
<a asp-controller="Client" asp-action="ProfileAsync" asp-route-id="@stat.ClientId">
|
||||
<color-code value="@stat.Name" allow="ViewBag.EnableColorCodes"></color-code>
|
||||
</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a asp-controller="ClientStatistics" asp-action="Advanced" asp-route-id="@stat.ClientId">
|
||||
<color-code value="@stat.Name" allow="ViewBag.EnableColorCodes"></color-code>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (ViewBag.UseNewStats)
|
||||
{
|
||||
<div class="d-flex flex-column">
|
||||
<div>
|
||||
<span class="text-primary font-weight-bold h5">
|
||||
<div class="font-size-14">
|
||||
<span class="text-primary">
|
||||
@stat.Performance.ToNumericalString()
|
||||
</span>
|
||||
@if (stat.ServerId == null)
|
||||
{
|
||||
<span class="text-muted font-weight-bold h5">@loc["WEBFRONT_ADV_STATS_RATING"].FormatExt("").ToLower()</span>
|
||||
<span class="text-muted">@loc["WEBFRONT_ADV_STATS_RATING"].FormatExt("").ToLower()</span>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<span class="text-muted font-weight-bold h5">@loc["WEBFRONT_ADV_STATS_PERFORMANCE"].FormatExt("").ToLower()</span>
|
||||
<span class="text-muted">@loc["WEBFRONT_ADV_STATS_PERFORMANCE"].FormatExt("").ToLower()</span>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.Kills.ToNumericalString()</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KILLS"]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.Deaths.ToNumericalString()</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_DEATHS"]</span><br />
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.KDR</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KDR"]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.TimePlayedValue.HumanizeForCurrentCulture() </span><span class="text-muted">@loc["WEBFRONT_PROFILE_PLAYER"]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary"> @stat.LastSeenValue.HumanizeForCurrentCulture() </span><span class="text-muted">@loc["WEBFRONT_PROFILE_LSEEN"]</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-primary">@stat.Performance</span> <span class="text-muted"> @loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"]</span>
|
||||
<br/>
|
||||
<span class="text-primary">@stat.KDR</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KDR"]</span>
|
||||
<span class="text-primary">@stat.Kills</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KILLS"]</span>
|
||||
<span class="text-primary">@stat.Deaths</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_DEATHS"]</span><br />
|
||||
<span class="text-muted">@loc["WEBFRONT_PROFILE_PLAYER"]</span> <span class="text-primary"> @stat.TimePlayed </span><span class="text-muted">@loc["GLOBAL_TIME_HOURS"]</span><br />
|
||||
<span class="text-muted">@loc["WEBFRONT_PROFILE_LSEEN"]</span><span class="text-primary"> @stat.LastSeen </span><span class="text-muted">@loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column font-size-12 text-right text-md-left">
|
||||
<div>
|
||||
<span class="text-primary">@stat.Kills.ToNumericalString()</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KILLS"]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.Deaths.ToNumericalString()</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_DEATHS"]</span><br/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.KDR</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KDR"]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary">@stat.TimePlayedValue.HumanizeForCurrentCulture() </span><span class="text-muted">@loc["WEBFRONT_PROFILE_PLAYER"]</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-primary"> @stat.LastSeenValue.HumanizeForCurrentCulture() </span><span class="text-muted">@loc["WEBFRONT_PROFILE_LSEEN"]</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 client-rating-graph" id="rating_history_@(stat.ClientId + "_" + stat.Id)" data-history="@Html.Raw(Json.Serialize(stat.PerformanceHistory))">
|
||||
|
||||
<div class="w-full w-md-half client-rating-graph" id="rating_history_@(stat.ClientId + "_" + stat.Id)" data-history="@Html.Raw(Json.Serialize(stat.PerformanceHistory))">
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 client-rating-icon text-md-right text-center align-items-center d-flex justify-content-center">
|
||||
@if (ViewBag.UseNewStats)
|
||||
{
|
||||
<img class="align-self-center d-none d-md-block" src="~/images/stats/ranks/rank_@(stat.ZScore.RankIconIndexForZScore()).png" alt="@stat.Performance"/>
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
<img src="/images/icons/@rankIcon(stat.Performance)"/>
|
||||
}
|
||||
<div class="w-quarter align-self-center d-flex justify-content-center">
|
||||
<img class="w-100 h-100" src="~/images/stats/ranks/rank_@(stat.ZScore.RankIconIndexForZScore()).png" alt="@stat.Performance"/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
@ -1,34 +1,48 @@
|
||||
<ul class="nav nav-tabs border-top border-bottom nav-fill row" role="tablist" id="stats_top_players">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active top-players-link" href="#server_0" role="tab" data-toggle="tab" aria-selected="true" data-serverid="0">@ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"]</a>
|
||||
</li>
|
||||
@model IEnumerable<SharedLibraryCore.Dtos.ServerInfo>
|
||||
@using WebfrontCore.ViewModels
|
||||
|
||||
@foreach (var server in ViewBag.Servers)
|
||||
{
|
||||
<li class="nav-item ">
|
||||
<a class="nav-link top-players-link" href="#server_@server.ID" role="tab" data-toggle="tab" aria-selected="false" data-serverid="@server.ID">
|
||||
<color-code value="@server.Name"></color-code>
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content border-bottom row">
|
||||
<div role="tabpanel" class="tab-pane active striped flex-fill" id="server_0">
|
||||
@await Component.InvokeAsync("TopPlayers", new { count = 25, offset = 0 })
|
||||
<div class="content mt-20 row">
|
||||
<div class="col-12 col-lg-9 col-xl-10 mt-0">
|
||||
<h2 class="content-title mb-0">Top Players</h2>
|
||||
<span class="text-muted">
|
||||
<color-code value="@(ViewBag.SelectedServerName ?? ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"])"></color-code>
|
||||
</span>
|
||||
|
||||
<div id="topPlayersContainer">
|
||||
@await Component.InvokeAsync("TopPlayers", new { count = 25, offset = 0, serverEndpoint = ViewBag.SelectedServerId })
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<i id="loaderLoad" class="oi oi-chevron-bottom loader-load-more text-primary mt-5" aria-hidden="true"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach (var server in ViewBag.Servers)
|
||||
{
|
||||
<div role="tabpanel" class="tab-pane striped flex-fill" id="server_@server.ID">
|
||||
</div>
|
||||
<!-- side context menu -->
|
||||
@{
|
||||
var menuItems = new SideContextMenuItems
|
||||
{
|
||||
MenuTitle = "Game", Items = Model.Select(server => new SideContextMenuItem
|
||||
{
|
||||
IsLink = true,
|
||||
Reference = Url.Action("TopPlayers", "Stats", new { serverId = server.Endpoint }),
|
||||
Title = server.Name.StripColors(),
|
||||
IsActive = ViewBag.SelectedServerId == server.Endpoint
|
||||
}).Prepend(new SideContextMenuItem
|
||||
{
|
||||
IsLink = true,
|
||||
Reference = Url.Action("TopPlayers", "Stats"),
|
||||
Title = ViewBag.Localization["WEBFRONT_STATS_INDEX_ALL_SERVERS"],
|
||||
IsActive = ViewBag.SelectedServerId is null
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
<partial name="_SideContextMenu" for="@menuItems"></partial>
|
||||
</div>
|
||||
|
||||
@section scripts
|
||||
{
|
||||
{
|
||||
<environment include="Development">
|
||||
<script type="text/javascript" src="~/js/loader.js"></script>
|
||||
<script type="text/javascript" src="~/js/stats.js"></script>
|
||||
</environment>
|
||||
<script>initLoader('/Stats/GetTopPlayersAsync', '#server_0', 25);</script>
|
||||
<script>initLoader('/Stats/GetTopPlayersAsync', '#topPlayersContainer', 25);</script>
|
||||
}
|
||||
|
@ -1,24 +1,25 @@
|
||||
@using SharedLibraryCore.Dtos.Meta.Responses
|
||||
@using Humanizer
|
||||
@model IList<MessageResponse>
|
||||
@{
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
<div class="client-message-context">
|
||||
<h5 class="bg-primary pt-2 pb-2 pl-3 mb-0 mt-2 text-white">@Model.First().When.ToString()</h5>
|
||||
<div class="bg-dark p-3 mb-2 border-bottom">
|
||||
<div class="client-message-context mt-10 mb-10">
|
||||
<h5 class="rounded-top bg-primary text-light mb-0 p-10 pt-5 pb-5">@Model.First().When.Humanize()</h5>
|
||||
<div class="bg-dark-dm bg-light-lm p-10 pr-20 rounded-bottom">
|
||||
@foreach (var message in Model)
|
||||
{
|
||||
<span class="text-white">
|
||||
<color-code value="@message.ClientName" allow="ViewBag.EnableColorCodes"></color-code>
|
||||
<span>
|
||||
<color-code value="@message.ClientName" allow="@ViewBag.EnableColorCodes"></color-code>
|
||||
</span>
|
||||
<span>
|
||||
—
|
||||
<span class="@(message.IsQuickMessage ? "font-italic" : "")">
|
||||
<color-code value="@(message.IsHidden ? message.HiddenMessage : message.Message)" allow="ViewBag.EnableColorCodes"></color-code>
|
||||
<span class="@(message.IsQuickMessage ? "font-italic" : "") text-light-dm text-dark-lm">
|
||||
<color-code value="@(message.IsHidden ? message.HiddenMessage : message.Message)" allow="@ViewBag.EnableColorCodes"></color-code>
|
||||
</span>
|
||||
</span>
|
||||
<br />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
Layout = null;
|
||||
}
|
||||
|
||||
<div class="penalty-info-context bg-dark p-2 mt-2 mb-2 border-top border-bottom">
|
||||
<div class="penalty-info-context bg-dark-dm bg-light-lm p-20 mt-5 mb-5 rounded-top rounded-bottom border-top border-bottom">
|
||||
@foreach (var snapshot in Model)
|
||||
{
|
||||
<!-- this is not ideal, but I didn't want to manually write out all the properties-->
|
||||
@ -15,9 +15,9 @@
|
||||
continue;
|
||||
}
|
||||
|
||||
<span class="text-white">@prop.Name </span>
|
||||
<span class="text-light-dm text-dark-lm">@prop.Name </span>
|
||||
<span>— @prop.GetValue(snapshot)?.ToString()?.StripColors()</span><br/>
|
||||
}
|
||||
<div class="w-100 mt-1 mb-1 border-bottom"></div>
|
||||
<hr class="mt-10 mb-10"/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user