diff --git a/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml b/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml
index 9d3506c6ba04f2..e5bc610f7ff462 100644
--- a/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml
+++ b/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml
@@ -61,8 +61,8 @@
-
-
+
+
diff --git a/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml.cs b/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml.cs
index 665b8eced02089..3ff408667a7579 100644
--- a/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml.cs
+++ b/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml.cs
@@ -1,5 +1,5 @@
using System.Linq;
-using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
using Content.Client.Administration.UI.CustomControls;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
@@ -15,13 +15,20 @@ namespace Content.Client.Administration.UI.Logs;
[GenerateTypedNameReferences]
public sealed partial class AdminLogsControl : Control
{
+ ///
+ /// List of used tags can be found here: Robust.Client/UserInterface/RichText/MarkupTagManager.cs
+ /// Pattern test online: https://regex101.com/r/3krK2I/2
+ ///
+ private const string BBCodeRegexPattern = "((\\[|\\[/)(color|cmdlink|font|bold|italic)=?\\w*\\])";
private readonly Comparer _adminLogTypeButtonComparer =
- Comparer.Create((a, b) =>
- string.Compare(a.Type.ToString(), b.Type.ToString(), StringComparison.Ordinal));
+ Comparer.Create(
+ (a, b) => string.Compare(a.Type.ToString(), b.Type.ToString(), StringComparison.Ordinal)
+ );
private readonly Comparer _adminLogPlayerButtonComparer =
- Comparer.Create((a, b) =>
- string.Compare(a.Text, b.Text, StringComparison.Ordinal));
+ Comparer.Create(
+ (a, b) => string.Compare(a.Text, b.Text, StringComparison.Ordinal)
+ );
public AdminLogsControl()
{
@@ -44,6 +51,8 @@ public AdminLogsControl()
ResetRoundButton.OnPressed += ResetRoundPressed;
+ RecievedLogs = new List();
+
SetImpacts(Enum.GetValues().OrderBy(impact => impact).ToArray());
SetTypes(Enum.GetValues());
}
@@ -55,6 +64,12 @@ public AdminLogsControl()
private int ShownLogs { get; set; }
private int TotalLogs { get; set; }
private int RoundLogs { get; set; }
+
+ ///
+ /// Storage of recieved logs
+ ///
+ private List RecievedLogs { get; set; }
+
public bool IncludeNonPlayerLogs { get; set; }
public HashSet SelectedTypes { get; } = new();
@@ -239,22 +254,47 @@ private void UpdatePlayers()
private void UpdateLogs()
{
ShownLogs = 0;
+ var logsText = "";
- foreach (var child in LogsContainer.Children)
+ // build logs string
+ for (var i = RecievedLogs.Count - 1; i >= 0; i--)
{
- if (child is not AdminLogLabel log)
+ var log = RecievedLogs[i];
+ if (ShouldShowLog(log))
{
- continue;
+ ShownLogs++;
+ logsText += string.Format(
+ "{0:HH:mm:ss} - {1}\n{2}\n\n",
+ log.Date,
+ log.Type,
+ log.Message
+ );
}
-
- child.Visible = ShouldShowLog(log);
- if (child.Visible)
+ }
+ // set new text in TextEdit and clear BB tags only in result log string to
+ // preserve original log messages for posible future use
+ AdminLogsTextEdit.TextRope = new Robust.Shared.Utility.Rope.Leaf(
+ Regex.Replace(logsText, BBCodeRegexPattern, "")
+ );
+ UpdateCount(ShownLogs, RecievedLogs.Count);
+ ScrollLogsToBottom();
+ }
+
+ ///
+ /// Try to scroll AdminLogsTextEdit to the end
+ ///
+ private void ScrollLogsToBottom()
+ {
+ // find scrollbar in TextEdit's children
+ // it must be at index 1, but may be changed in future
+ for (var i = 0; i < AdminLogsTextEdit.ChildCount; i++)
+ {
+ if (AdminLogsTextEdit.GetChild(i) is VScrollBar scrollbar)
{
- ShownLogs++;
+ scrollbar.ValueTarget = float.PositiveInfinity;
+ break;
}
}
-
- UpdateCount();
}
private bool ShouldShowType(AdminLogTypeButton button)
@@ -269,30 +309,30 @@ private bool ShouldShowPlayer(AdminLogPlayerButton button)
button.Text.Contains(PlayerSearch.Text, StringComparison.OrdinalIgnoreCase);
}
- private bool LogMatchesPlayerFilter(AdminLogLabel label)
+ private bool LogMatchesPlayerFilter(SharedAdminLog log)
{
- if (label.Log.Players.Length == 0)
+ if (log.Players.Length == 0)
return SelectedPlayers.Count == 0 || IncludeNonPlayerLogs;
- return SelectedPlayers.Overlaps(label.Log.Players);
+ return SelectedPlayers.Overlaps(log.Players);
}
- private bool ShouldShowLog(AdminLogLabel label)
+ private bool ShouldShowLog(SharedAdminLog log)
{
// Check log type
- if (!SelectedTypes.Contains(label.Log.Type))
+ if (!SelectedTypes.Contains(log.Type))
return false;
// Check players
- if (!LogMatchesPlayerFilter(label))
+ if (!LogMatchesPlayerFilter(log))
return false;
// Check impact
- if (!SelectedImpacts.Contains(label.Log.Impact))
+ if (!SelectedImpacts.Contains(log.Impact))
return false;
// Check search
- if (!label.Log.Message.Contains(LogSearch.Text, StringComparison.OrdinalIgnoreCase))
+ if (!log.Message.Contains(LogSearch.Text, StringComparison.OrdinalIgnoreCase))
return false;
return true;
@@ -458,32 +498,14 @@ public void SetPlayers(Dictionary players)
public void AddLogs(List logs)
{
- var span = CollectionsMarshal.AsSpan(logs);
- for (var i = 0; i < span.Length; i++)
- {
- ref var log = ref span[i];
- var separator = new HSeparator();
- var label = new AdminLogLabel(ref log, separator);
- label.Visible = ShouldShowLog(label);
-
- TotalLogs++;
- if (label.Visible)
- {
- ShownLogs++;
- }
-
- LogsContainer.AddChild(label);
- LogsContainer.AddChild(separator);
- }
-
- UpdateCount();
+ RecievedLogs.AddRange(logs);
+ UpdateLogs();
}
public void SetLogs(List logs)
{
- LogsContainer.RemoveAllChildren();
- UpdateCount(0, 0);
- AddLogs(logs);
+ RecievedLogs = logs;
+ UpdateLogs();
}
public void UpdateCount(int? shown = null, int? total = null, int? round = null)