Вернуть команду adminwho в общий доступ и реализовать UI с правильным client-server взаимодействием (#2918)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: VigersRay <60344369+VigersRay@users.noreply.github.com> Co-authored-by: Vigers Ray <vigersray@gmail.com>
This commit is contained in:
parent
5d085ad9c8
commit
878167c937
15 changed files with 388 additions and 5 deletions
31
Content.Client/Administration/Systems/AdminWhoSystem.cs
Normal file
31
Content.Client/Administration/Systems/AdminWhoSystem.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using Content.Shared.Administration;
|
||||
|
||||
namespace Content.Client.Administration.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Client system for handling admin who requests
|
||||
/// </summary>
|
||||
public sealed class AdminWhoSystem : EntitySystem
|
||||
{
|
||||
public event Action<List<AdminWhoEntry>>? OnAdminWhoUpdate;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<AdminWhoResponseEvent>(OnAdminWhoResponse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request the list of online administrators from the server
|
||||
/// </summary>
|
||||
public void RequestAdminWho()
|
||||
{
|
||||
RaiseNetworkEvent(new RequestAdminWhoEvent());
|
||||
}
|
||||
|
||||
private void OnAdminWhoResponse(AdminWhoResponseEvent args, EntitySessionEventArgs session)
|
||||
{
|
||||
OnAdminWhoUpdate?.Invoke(args.Admins);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
using Content.Client.Administration.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
|
||||
namespace Content.Client.Administration.UI.Bwoink
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed class AdminWhoUIController : UIController, IOnSystemChanged<AdminWhoSystem>
|
||||
{
|
||||
private AdminWhoWindow? _dialog;
|
||||
private AdminWhoSystem? _adminWhoSystem;
|
||||
|
||||
protected override string SawmillName => "c.c.admin.adminwho";
|
||||
|
||||
public void OnSystemLoaded(AdminWhoSystem system)
|
||||
{
|
||||
_adminWhoSystem = system;
|
||||
|
||||
_dialog = new AdminWhoWindow();
|
||||
_dialog.Initialize(system);
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(AdminWhoSystem system)
|
||||
{
|
||||
if (_dialog != null)
|
||||
{
|
||||
_dialog.Close();
|
||||
_dialog.Uninitialize();
|
||||
_dialog.Dispose();
|
||||
_dialog = null;
|
||||
}
|
||||
|
||||
_adminWhoSystem = null;
|
||||
}
|
||||
|
||||
public void Open()
|
||||
{
|
||||
if (_dialog == null)
|
||||
{
|
||||
if (_adminWhoSystem == null)
|
||||
return;
|
||||
|
||||
_dialog = new AdminWhoWindow();
|
||||
_dialog.Initialize(_adminWhoSystem);
|
||||
}
|
||||
|
||||
_dialog.OpenCentered();
|
||||
_dialog.RefreshAdminList();
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
if (_dialog?.IsOpen == true)
|
||||
Close();
|
||||
else
|
||||
Open();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_dialog?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Content.Client/Administration/UI/Bwoink/AdminWhoWindow.xaml
Normal file
23
Content.Client/Administration/UI/Bwoink/AdminWhoWindow.xaml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<ui:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
VerticalExpand="True" HorizontalExpand="True"
|
||||
Title="{Loc admin-who-title}"
|
||||
SetSize="400 300"
|
||||
Resizable="False">
|
||||
<PanelContainer StyleClasses="BackgroundDark">
|
||||
<BoxContainer Orientation="Vertical" Margin="8">
|
||||
<Label Name="LoadingLabel" Access="Public" Text="{Loc admin-who-loading}" StyleClasses="LabelText"
|
||||
HorizontalAlignment="Center" Visible="False" />
|
||||
<Label Name="NoAdminsLabel" Access="Public" Text="{Loc admin-who-no-admins}" StyleClasses="LabelText"
|
||||
HorizontalAlignment="Center" Visible="False" />
|
||||
<ScrollContainer VerticalExpand="True" HorizontalExpand="True" HScrollEnabled="False">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" Name="AdminsContainer" Access="Public" VerticalExpand="True" />
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center" Margin="0 8 0 0">
|
||||
<Button Name="RefreshButton" Access="Public" Text="{Loc admin-who-refresh}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</ui:FancyWindow>
|
||||
102
Content.Client/Administration/UI/Bwoink/AdminWhoWindow.xaml.cs
Normal file
102
Content.Client/Administration/UI/Bwoink/AdminWhoWindow.xaml.cs
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
using System.Text;
|
||||
using Content.Client.Administration.Managers;
|
||||
using Content.Client.Administration.Systems;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Administration.UI.Bwoink
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminWhoWindow : FancyWindow
|
||||
{
|
||||
private AdminWhoSystem? _adminWhoSystem;
|
||||
|
||||
public AdminWhoWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
RefreshButton.OnPressed += _ => RefreshAdminList();
|
||||
CloseButton.OnPressed += _ => Close();
|
||||
}
|
||||
|
||||
public void Initialize(AdminWhoSystem system)
|
||||
{
|
||||
_adminWhoSystem = system;
|
||||
_adminWhoSystem.OnAdminWhoUpdate += OnAdminListReceived;
|
||||
|
||||
// Request the list when the window is initialized
|
||||
RefreshAdminList();
|
||||
}
|
||||
|
||||
public void Uninitialize()
|
||||
{
|
||||
if (_adminWhoSystem != null)
|
||||
{
|
||||
_adminWhoSystem.OnAdminWhoUpdate -= OnAdminListReceived;
|
||||
_adminWhoSystem = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshAdminList()
|
||||
{
|
||||
AdminsContainer.RemoveAllChildren();
|
||||
|
||||
NoAdminsLabel.Visible = false;
|
||||
LoadingLabel.Visible = true;
|
||||
|
||||
_adminWhoSystem?.RequestAdminWho();
|
||||
}
|
||||
|
||||
private void OnAdminListReceived(List<AdminWhoEntry> admins)
|
||||
{
|
||||
LoadingLabel.Visible = false;
|
||||
|
||||
if (admins.Count == 0)
|
||||
{
|
||||
NoAdminsLabel.Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
NoAdminsLabel.Visible = false;
|
||||
|
||||
// Add each admin
|
||||
foreach (var admin in admins)
|
||||
{
|
||||
var adminText = new StringBuilder();
|
||||
adminText.Append(admin.Name);
|
||||
|
||||
if (!string.IsNullOrEmpty(admin.Title))
|
||||
adminText.Append($": [{admin.Title}]");
|
||||
|
||||
if (admin.IsStealth)
|
||||
adminText.Append(" (S)");
|
||||
|
||||
if (admin.IsAfk)
|
||||
adminText.Append(" [AFK]");
|
||||
|
||||
var adminLabel = new Label
|
||||
{
|
||||
Text = adminText.ToString(),
|
||||
StyleClasses = { "LabelText" },
|
||||
HorizontalAlignment = Control.HAlignment.Left,
|
||||
Margin = new Thickness(16, 2, 8, 2)
|
||||
};
|
||||
AdminsContainer.AddChild(adminLabel);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Uninitialize();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
<CheckBox Name="PlaySound" Access="Public" Text="{Loc 'admin-bwoink-play-sound'}" Pressed="True" />
|
||||
<Control HorizontalExpand="True" MinWidth="5" />
|
||||
<Button Visible="True" Name="PopOut" Access="Public" Text="{Loc 'admin-logs-pop-out'}" StyleClasses="OpenBoth" HorizontalAlignment="Left" />
|
||||
<Control HorizontalExpand="True" MinWidth="5" />
|
||||
<Button Visible="True" Name="AdminWho" Access="Public" Text="{Loc 'admin-who-button'}" StyleClasses="OpenBoth" HorizontalAlignment="Left" />
|
||||
<Control HorizontalExpand="True" />
|
||||
<Button Visible="False" Name="Bans" Text="{Loc 'admin-player-actions-bans'}" StyleClasses="OpenRight" />
|
||||
<Button Visible="False" Name="Notes" Text="{Loc 'admin-player-actions-notes'}" StyleClasses="OpenBoth" />
|
||||
|
|
|
|||
|
|
@ -203,6 +203,14 @@ namespace Content.Client.Administration.UI.Bwoink
|
|||
{
|
||||
uiController.PopOut();
|
||||
};
|
||||
|
||||
// Sunrise-Start
|
||||
AdminWho.OnPressed += _ =>
|
||||
{
|
||||
var ctrl = _ui.GetUIController<AdminWhoUIController>();
|
||||
ctrl.Toggle();
|
||||
};
|
||||
// Sunrise-End
|
||||
}
|
||||
|
||||
public void OnBwoink(NetUserId channel)
|
||||
|
|
|
|||
|
|
@ -8,4 +8,9 @@
|
|||
<RichTextLabel Name="TypingIndicator" Access="Public" />
|
||||
<HistoryLineEdit Name="SenderLineEdit" />
|
||||
<RichTextLabel Name="RelayedToDiscordLabel" Access="Public" Visible="False" />
|
||||
<!-- Sunrise-Start -->
|
||||
<BoxContainer Orientation="Horizontal" Margin="0 4 0 0">
|
||||
<Button Name="AdminWhoButton" Access="Public" Text="{Loc 'admin-who-button'}" Visible="False" HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
<!-- Sunrise-End -->
|
||||
</BoxContainer>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Timing;
|
||||
|
|
@ -10,6 +11,8 @@ namespace Content.Client.Administration.UI.Bwoink
|
|||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BwoinkPanel : BoxContainer
|
||||
{
|
||||
[Dependency] private readonly IUserInterfaceManager _ui = default!;
|
||||
|
||||
private readonly Action<string> _messageSender;
|
||||
|
||||
public int Unread { get; private set; } = 0;
|
||||
|
|
@ -25,6 +28,7 @@ namespace Content.Client.Administration.UI.Bwoink
|
|||
public BwoinkPanel(Action<string> messageSender)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this); // Sunrise-Edit
|
||||
|
||||
var msg = new FormattedMessage();
|
||||
msg.PushColor(Color.LightGray);
|
||||
|
|
@ -41,6 +45,15 @@ namespace Content.Client.Administration.UI.Bwoink
|
|||
};
|
||||
SenderLineEdit.OnTextEntered += Input_OnTextEntered;
|
||||
SenderLineEdit.OnTextChanged += Input_OnTextChanged;
|
||||
|
||||
// Sunrise-Start
|
||||
AdminWhoButton.OnPressed += _ =>
|
||||
{
|
||||
var ctrl = _ui.GetUIController<AdminWhoUIController>();
|
||||
ctrl.Toggle();
|
||||
};
|
||||
// Sunrise-End
|
||||
|
||||
UpdateTypingIndicator();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -637,7 +637,10 @@ public sealed class UserAHelpUIHandler : IAHelpUIHandler
|
|||
if (_window is { Disposed: false })
|
||||
return;
|
||||
_chatPanel = new BwoinkPanel(text => SendMessageAction?.Invoke(_ownerId, text, true, false));
|
||||
_chatPanel.AHelpDescLabel.Visible = true; // Sunrise-Edit
|
||||
// Sunrise-Start
|
||||
_chatPanel.AHelpDescLabel.Visible = true;
|
||||
_chatPanel.AdminWhoButton.Visible = true;
|
||||
// Sunrise-End
|
||||
_chatPanel.InputTextChanged += text => InputTextChanged?.Invoke(_ownerId, text);
|
||||
_chatPanel.RelayedToDiscordLabel.Visible = relayActive;
|
||||
_window = new DefaultWindow()
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Horizontal" SetHeight="40" HorizontalExpand="True" Margin="5">
|
||||
<Button Name="NewTicketButton" Access="Public" Text="{Loc 'mentor-help-new-ticket'}"
|
||||
StyleClasses="ButtonBig" />
|
||||
<Control SetWidth="10" />
|
||||
StyleClasses="ButtonBig" Margin="0 0 10 0"/>
|
||||
<Button Name="AdminWhoButton" Access="Public" Text="{Loc 'admin-who-button'}" Margin="0 0 10 0" />
|
||||
<Button Name="StatisticsButton" Access="Public" Text="{Loc 'mentor-help-statistics'}"
|
||||
StyleClasses="ButtonBig" Visible="False" />
|
||||
StyleClasses="ButtonBig" Visible="False" Margin="0 0 10 0" />
|
||||
<Control HorizontalExpand="True" />
|
||||
<Button Name="BackToListButton" Access="Public" Text="{Loc 'mentor-help-back-to-list'}"
|
||||
StyleClasses="ButtonBig" Visible="False" />
|
||||
StyleClasses="ButtonBig" HorizontalAlignment="Right" Visible="False" />
|
||||
</BoxContainer>
|
||||
|
||||
<Control Name="DefaultState" VerticalExpand="True" HorizontalExpand="True">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
using System.Linq;
|
||||
using Content.Client.Administration.Systems;
|
||||
using Content.Client.Administration.UI.Bwoink;
|
||||
using Content.Shared._Sunrise.MentorHelp;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Database;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.State;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
|
@ -65,6 +67,12 @@ namespace Content.Client._Sunrise.MentorHelp
|
|||
// Handle tab changes to load closed tickets when needed
|
||||
TicketsTabContainer.OnTabChanged += OnTabChanged;
|
||||
|
||||
AdminWhoButton.OnPressed += _ =>
|
||||
{
|
||||
var ctrl = _ui.GetUIController<AdminWhoUIController>();
|
||||
ctrl.Toggle();
|
||||
};
|
||||
|
||||
// Set initial state
|
||||
SwitchState(ViewState.TicketsList);
|
||||
}
|
||||
|
|
|
|||
64
Content.Server/Administration/Systems/AdminWhoSystem.cs
Normal file
64
Content.Server/Administration/Systems/AdminWhoSystem.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Afk;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Administration.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Server system for handling admin who requests
|
||||
/// </summary>
|
||||
public sealed class AdminWhoSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IAfkManager _afkManager = default!;
|
||||
[Dependency] private readonly IAdminManager _adminManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<RequestAdminWhoEvent>(OnRequestAdminWho);
|
||||
}
|
||||
|
||||
private void OnRequestAdminWho(RequestAdminWhoEvent args, EntitySessionEventArgs session)
|
||||
{
|
||||
if (session.SenderSession == null)
|
||||
return;
|
||||
|
||||
var seeStealth = false;
|
||||
var seeAfk = false;
|
||||
|
||||
// Check if the requesting player can see stealth admins and AFK status
|
||||
if (session.SenderSession.AttachedEntity != null)
|
||||
{
|
||||
var playerData = _adminManager.GetAdminData(session.SenderSession);
|
||||
if (playerData != null)
|
||||
{
|
||||
seeStealth = playerData.CanStealth();
|
||||
seeAfk = _adminManager.HasAdminFlag(session.SenderSession, AdminFlags.Admin);
|
||||
}
|
||||
}
|
||||
|
||||
var adminList = new List<AdminWhoEntry>();
|
||||
|
||||
foreach (var admin in _adminManager.ActiveAdmins)
|
||||
{
|
||||
var adminData = _adminManager.GetAdminData(admin);
|
||||
DebugTools.AssertNotNull(adminData);
|
||||
|
||||
if (adminData!.Stealth && !seeStealth)
|
||||
continue;
|
||||
|
||||
var isAfk = seeAfk && _afkManager.IsAfk(admin);
|
||||
|
||||
adminList.Add(new AdminWhoEntry(
|
||||
admin.Name,
|
||||
adminData.Title,
|
||||
adminData.Stealth,
|
||||
isAfk
|
||||
));
|
||||
}
|
||||
|
||||
RaiseNetworkEvent(new AdminWhoResponseEvent(adminList), session.SenderSession);
|
||||
}
|
||||
}
|
||||
45
Content.Shared/Administration/AdminWhoSystem.cs
Normal file
45
Content.Shared/Administration/AdminWhoSystem.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Administration;
|
||||
|
||||
/// <summary>
|
||||
/// Request event to get the list of online administrators
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestAdminWhoEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response event containing the list of online administrators
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class AdminWhoResponseEvent : EntityEventArgs
|
||||
{
|
||||
public readonly List<AdminWhoEntry> Admins;
|
||||
|
||||
public AdminWhoResponseEvent(List<AdminWhoEntry> admins)
|
||||
{
|
||||
Admins = admins;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a single administrator
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class AdminWhoEntry
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly string? Title;
|
||||
public readonly bool IsStealth;
|
||||
public readonly bool IsAfk;
|
||||
|
||||
public AdminWhoEntry(string name, string? title, bool isStealth, bool isAfk)
|
||||
{
|
||||
Name = name;
|
||||
Title = title;
|
||||
IsStealth = isStealth;
|
||||
IsAfk = isAfk;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
admin-who-button = Admins Online
|
||||
admin-who-title = Online Administrators
|
||||
admin-who-refresh = Refresh
|
||||
admin-who-close = Close
|
||||
admin-who-no-admins = No administrators are currently online.
|
||||
admin-who-loading = Loading administrators...
|
||||
admin-who-info = This feature displays which administrators are currently online and available to help with any issues you may have.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
admin-who-button = Админы онлайн
|
||||
admin-who-title = Администраторы онлайн
|
||||
admin-who-refresh = Обновить
|
||||
admin-who-close = Закрыть
|
||||
admin-who-no-admins = В данный момент нет администраторов онлайн.
|
||||
admin-who-loading = Загрузка администраторов...
|
||||
admin-who-info = Эта функция показывает, какие администраторы в данный момент онлайн и доступны для помощи с любыми вопросами.
|
||||
Loading…
Add table
Reference in a new issue