Merge pull request 'Changes of admin ui for banning users.' (#128) from ban-admin-changes into 2.0.3
Reviewed-on: #128
This commit was merged in pull request #128.
This commit is contained in:
@@ -8,6 +8,7 @@ using LightlessSync.UI.Tags;
|
||||
using LightlessSync.WebAPI;
|
||||
using LightlessSync.UI.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using LightlessSync.PlayerData.Factories;
|
||||
|
||||
namespace LightlessSync.Services;
|
||||
|
||||
@@ -23,6 +24,7 @@ public class UiFactory
|
||||
private readonly PerformanceCollectorService _performanceCollectorService;
|
||||
private readonly ProfileTagService _profileTagService;
|
||||
private readonly DalamudUtilService _dalamudUtilService;
|
||||
private readonly PairFactory _pairFactory;
|
||||
|
||||
public UiFactory(
|
||||
ILoggerFactory loggerFactory,
|
||||
@@ -34,7 +36,8 @@ public class UiFactory
|
||||
LightlessProfileManager lightlessProfileManager,
|
||||
PerformanceCollectorService performanceCollectorService,
|
||||
ProfileTagService profileTagService,
|
||||
DalamudUtilService dalamudUtilService)
|
||||
DalamudUtilService dalamudUtilService,
|
||||
PairFactory pairFactory)
|
||||
{
|
||||
_loggerFactory = loggerFactory;
|
||||
_lightlessMediator = lightlessMediator;
|
||||
@@ -46,6 +49,7 @@ public class UiFactory
|
||||
_performanceCollectorService = performanceCollectorService;
|
||||
_profileTagService = profileTagService;
|
||||
_dalamudUtilService = dalamudUtilService;
|
||||
_pairFactory = pairFactory;
|
||||
}
|
||||
|
||||
public SyncshellAdminUI CreateSyncshellAdminUi(GroupFullInfoDto dto)
|
||||
@@ -58,7 +62,8 @@ public class UiFactory
|
||||
_pairUiService,
|
||||
dto,
|
||||
_performanceCollectorService,
|
||||
_lightlessProfileManager);
|
||||
_lightlessProfileManager,
|
||||
_pairFactory);
|
||||
}
|
||||
|
||||
public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair)
|
||||
|
||||
@@ -4,9 +4,11 @@ using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Data.Enum;
|
||||
using LightlessSync.API.Data.Extensions;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
using LightlessSync.PlayerData.Factories;
|
||||
using LightlessSync.PlayerData.Pairs;
|
||||
using LightlessSync.Services;
|
||||
using LightlessSync.Services.Mediator;
|
||||
@@ -42,13 +44,32 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
private Task<int>? _pruneTask;
|
||||
private int _pruneDays = 14;
|
||||
|
||||
// Ban management fields
|
||||
private Task<List<BannedGroupUserDto>>? _bannedUsersTask;
|
||||
private bool _bannedUsersLoaded;
|
||||
private string? _bannedUsersLoadError;
|
||||
|
||||
private string _newBanUid = string.Empty;
|
||||
private string _newBanReason = string.Empty;
|
||||
private Task? _newBanTask;
|
||||
private string? _newBanError;
|
||||
private DateTime _newBanBusyUntilUtc;
|
||||
|
||||
// Ban editing fields
|
||||
private string? _editingBanUid;
|
||||
private readonly Dictionary<string, string> _banReasonEdits = new(StringComparer.Ordinal);
|
||||
|
||||
private Task? _banEditTask;
|
||||
private string? _banEditError;
|
||||
|
||||
private Task<GroupPruneSettingsDto>? _pruneSettingsTask;
|
||||
private bool _pruneSettingsLoaded;
|
||||
private bool _autoPruneEnabled;
|
||||
private int _autoPruneDays = 14;
|
||||
private readonly PairFactory _pairFactory;
|
||||
|
||||
public SyncshellAdminUI(ILogger<SyncshellAdminUI> logger, LightlessMediator mediator, ApiController apiController,
|
||||
UiSharedService uiSharedService, PairUiService pairUiService, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager)
|
||||
UiSharedService uiSharedService, PairUiService pairUiService, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager, PairFactory pairFactory)
|
||||
: base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GroupAliasOrGID + ")", performanceCollectorService)
|
||||
{
|
||||
GroupFullInfo = groupFullInfo;
|
||||
@@ -76,6 +97,7 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
MaximumSize = new(700, 2000),
|
||||
};
|
||||
_pairUiService = pairUiService;
|
||||
_pairFactory = pairFactory;
|
||||
}
|
||||
|
||||
public GroupFullInfoDto GroupFullInfo { get; private set; }
|
||||
@@ -654,34 +676,345 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
_uiSharedService.MediumText("User Bans", UIColors.Get("LightlessYellow"));
|
||||
ImGuiHelpers.ScaledDummy(3f);
|
||||
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Retweet, "Refresh Banlist from Server"))
|
||||
EnsureBanListLoaded();
|
||||
|
||||
DrawNewBanEntryRow();
|
||||
|
||||
ImGuiHelpers.ScaledDummy(4f);
|
||||
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Retweet, "Refresh Banlist"))
|
||||
{
|
||||
_bannedUsers = _apiController.GroupGetBannedUsers(new GroupDto(GroupFullInfo.Group)).Result;
|
||||
QueueBanListRefresh(force: true);
|
||||
}
|
||||
|
||||
ImGuiHelpers.ScaledDummy(2f);
|
||||
|
||||
if (!_bannedUsersLoaded)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Loading banlist from server...", ImGuiColors.DalamudGrey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_bannedUsersLoadError))
|
||||
{
|
||||
UiSharedService.ColorTextWrapped(_bannedUsersLoadError!, ImGuiColors.DalamudRed);
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.BeginChild("bannedListScroll#" + GroupFullInfo.GID, new Vector2(0, 0), true);
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
float fullW = ImGui.GetContentRegionAvail().X;
|
||||
float scale = ImGuiHelpers.GlobalScale;
|
||||
|
||||
float frame = ImGui.GetFrameHeight();
|
||||
float actionIcons = 3;
|
||||
float colActions = actionIcons * frame + (actionIcons - 1) * style.ItemSpacing.X + 10f * scale;
|
||||
|
||||
float colIdentity = fullW * 0.45f;
|
||||
float colMeta = fullW * 0.35f;
|
||||
float colActions = fullW - colIdentity - colMeta - style.ItemSpacing.X * 2.0f;
|
||||
|
||||
// Header
|
||||
float colIdentity = fullW - colMeta - colActions - style.ItemSpacing.X * 2.0f;
|
||||
|
||||
float minIdentity = fullW * 0.40f;
|
||||
if (colIdentity < minIdentity)
|
||||
{
|
||||
colIdentity = minIdentity;
|
||||
colMeta = fullW - colIdentity - colActions - style.ItemSpacing.X * 2.0f;
|
||||
if (colMeta < 80f * scale) colMeta = 80f * scale;
|
||||
}
|
||||
|
||||
DrawBannedListHeader(colIdentity, colMeta);
|
||||
|
||||
int rowIndex = 0;
|
||||
foreach (var bannedUser in _bannedUsers.ToList())
|
||||
{
|
||||
// Each row
|
||||
DrawBannedRow(bannedUser, rowIndex++, colIdentity, colMeta, colActions);
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
|
||||
private void DrawNewBanEntryRow()
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("LightlessYellow"));
|
||||
ImGui.TextUnformatted("Add new ban");
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
UiSharedService.TextWrapped("Enter a UID (Not Alias!) and optional reason. (Hold CTRL to enable the ban button.)");
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
float fullW = ImGui.GetContentRegionAvail().X;
|
||||
|
||||
float uidW = fullW * 0.35f;
|
||||
float reasonW = fullW * 0.50f;
|
||||
float btnW = fullW - uidW - reasonW - style.ItemSpacing.X * 2f;
|
||||
|
||||
// UID
|
||||
ImGui.SetNextItemWidth(uidW);
|
||||
ImGui.InputTextWithHint("##newBanUid", "UID...", ref _newBanUid, 128);
|
||||
|
||||
// Reason
|
||||
ImGui.SameLine(0f, style.ItemSpacing.X);
|
||||
ImGui.SetNextItemWidth(reasonW);
|
||||
ImGui.InputTextWithHint("##newBanReason", "Reason (optional)...", ref _newBanReason, 256);
|
||||
|
||||
// Ban button
|
||||
ImGui.SameLine(0f, style.ItemSpacing.X);
|
||||
|
||||
var trimmedUid = (_newBanUid ?? string.Empty).Trim();
|
||||
var now = DateTime.UtcNow;
|
||||
bool taskRunning = _newBanTask != null && !_newBanTask.IsCompleted;
|
||||
bool busyLatched = now < _newBanBusyUntilUtc;
|
||||
bool busy = taskRunning || busyLatched;
|
||||
|
||||
bool canBan = UiSharedService.CtrlPressed()
|
||||
&& !string.IsNullOrWhiteSpace(_newBanUid)
|
||||
&& !busy;
|
||||
|
||||
using (ImRaii.Disabled(!canBan))
|
||||
using (ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("DimRed")))
|
||||
{
|
||||
ImGui.SetNextItemWidth(btnW);
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserSlash, "Ban"))
|
||||
{
|
||||
_newBanError = null;
|
||||
|
||||
_newBanBusyUntilUtc = DateTime.UtcNow.AddMilliseconds(750);
|
||||
|
||||
_newBanTask = SubmitNewBanByUidAsync(trimmedUid, _newBanReason);
|
||||
}
|
||||
}
|
||||
UiSharedService.AttachToolTip("Hold CTRL to enable banning by UID.");
|
||||
|
||||
if (busy)
|
||||
{
|
||||
UiSharedService.ColorTextWrapped("Banning user...", ImGuiColors.DalamudGrey);
|
||||
}
|
||||
|
||||
if (_newBanTask != null && _newBanTask.IsCompleted && DateTime.UtcNow >= _newBanBusyUntilUtc)
|
||||
{
|
||||
if (_newBanTask.IsFaulted)
|
||||
{
|
||||
var _ = _newBanTask.Exception;
|
||||
_newBanError ??= "Ban failed (see log).";
|
||||
}
|
||||
|
||||
QueueBanListRefresh(force: true);
|
||||
_newBanTask = null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SubmitNewBanByUidAsync(string uidOrAlias, string reason)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
uidOrAlias = (uidOrAlias ?? string.Empty).Trim();
|
||||
reason = (reason ?? string.Empty).Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(uidOrAlias))
|
||||
{
|
||||
_newBanError = "UID is empty.";
|
||||
return;
|
||||
}
|
||||
|
||||
string targetUid = uidOrAlias;
|
||||
string? typedAlias = null;
|
||||
|
||||
var snap = _pairUiService.GetSnapshot();
|
||||
if (snap.GroupPairs.TryGetValue(GroupFullInfo, out var pairs))
|
||||
{
|
||||
var match = pairs.FirstOrDefault(p =>
|
||||
string.Equals(p.UserData.UID, uidOrAlias, StringComparison.Ordinal) ||
|
||||
string.Equals(p.UserData.AliasOrUID, uidOrAlias, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
targetUid = match.UserData.UID;
|
||||
typedAlias = match.UserData.Alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
typedAlias = null;
|
||||
}
|
||||
}
|
||||
|
||||
var userData = new UserData(UID: targetUid, Alias: typedAlias);
|
||||
|
||||
await _apiController
|
||||
.GroupBanUser(new GroupPairDto(GroupFullInfo.Group, userData), reason)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
_newBanUid = string.Empty;
|
||||
_newBanReason = string.Empty;
|
||||
_newBanError = null;
|
||||
|
||||
QueueBanListRefresh(force: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to ban '{uidOrAlias}' in group {gid}", uidOrAlias, GroupFullInfo.Group.GID);
|
||||
_newBanError = "Failed to ban user (see log).";
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveBanReasonViaBanUserAsync(string uid)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_banReasonEdits.TryGetValue(uid, out var newReason))
|
||||
newReason = string.Empty;
|
||||
|
||||
newReason = (newReason ?? string.Empty).Trim();
|
||||
|
||||
var userData = new UserData(uid.Trim());
|
||||
|
||||
await _apiController
|
||||
.GroupBanUser(new GroupPairDto(GroupFullInfo.Group, userData), newReason)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
_editingBanUid = null;
|
||||
_banEditError = null;
|
||||
|
||||
await Task.Delay(450).ConfigureAwait(false);
|
||||
|
||||
QueueBanListRefresh(force: true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to edit ban reason for {uid} in group {gid}", uid, GroupFullInfo.Group.GID);
|
||||
_banEditError = "Failed to update reason (see log).";
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBannedRow(BannedGroupUserDto bannedUser, int rowIndex, float colIdentity, float colMeta, float colActions)
|
||||
{
|
||||
using var id = ImRaii.PushId("banRow_" + bannedUser.UID);
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
float x0 = ImGui.GetCursorPosX();
|
||||
|
||||
if (rowIndex % 2 == 0)
|
||||
{
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
var pMin = ImGui.GetCursorScreenPos();
|
||||
var rowHeight = ImGui.GetTextLineHeightWithSpacing() * 2.6f;
|
||||
var pMax = new Vector2(
|
||||
pMin.X + colIdentity + colMeta + colActions + style.ItemSpacing.X * 2.0f,
|
||||
pMin.Y + rowHeight);
|
||||
|
||||
var bgColor = UIColors.Get("FullBlack").WithAlpha(0.10f);
|
||||
drawList.AddRectFilled(pMin, pMax, ImGui.ColorConvertFloat4ToU32(bgColor));
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosX(x0);
|
||||
ImGui.AlignTextToFramePadding();
|
||||
|
||||
string alias = bannedUser.UserAlias ?? string.Empty;
|
||||
string line1 = string.IsNullOrEmpty(alias)
|
||||
? bannedUser.UID
|
||||
: $"{alias} ({bannedUser.UID})";
|
||||
|
||||
ImGui.TextUnformatted(line1);
|
||||
|
||||
var fullReason = bannedUser.Reason ?? string.Empty;
|
||||
|
||||
if (string.Equals(_editingBanUid, bannedUser.UID, StringComparison.Ordinal))
|
||||
{
|
||||
_banReasonEdits.TryGetValue(bannedUser.UID, out var editReason);
|
||||
editReason ??= StripAliasSuffix(fullReason);
|
||||
|
||||
ImGui.SetCursorPosX(x0);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||
ImGui.SetNextItemWidth(colIdentity);
|
||||
ImGui.InputTextWithHint("##banReasonEdit", "Reason...", ref editReason, 255);
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
_banReasonEdits[bannedUser.UID] = editReason;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_banEditError))
|
||||
UiSharedService.ColorTextWrapped(_banEditError!, ImGuiColors.DalamudRed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(fullReason))
|
||||
{
|
||||
ImGui.SetCursorPosX(x0);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||
|
||||
ImGui.PushTextWrapPos(x0 + colIdentity);
|
||||
UiSharedService.TextWrapped(fullReason);
|
||||
ImGui.PopTextWrapPos();
|
||||
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(x0 + colIdentity + style.ItemSpacing.X);
|
||||
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted($"By: {bannedUser.BannedBy}");
|
||||
|
||||
var dateText = bannedUser.BannedOn.ToLocalTime().ToString(CultureInfo.CurrentCulture);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||
ImGui.TextUnformatted(dateText);
|
||||
ImGui.PopStyleColor();
|
||||
ImGui.SameLine();
|
||||
|
||||
float frame = ImGui.GetFrameHeight();
|
||||
float actionsX0 = x0 + colIdentity + colMeta + style.ItemSpacing.X * 2.0f;
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(actionsX0);
|
||||
|
||||
bool isEditing = string.Equals(_editingBanUid, bannedUser.UID, StringComparison.Ordinal);
|
||||
int actionCount = 1 + (isEditing ? 2 : 1);
|
||||
|
||||
float totalW = actionCount * frame + (actionCount - 1) * style.ItemSpacing.X;
|
||||
float startX = actionsX0 + MathF.Max(0, colActions - totalW) - 36f;
|
||||
ImGui.SetCursorPosX(startX);
|
||||
|
||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Check))
|
||||
{
|
||||
_apiController.GroupUnbanUser(bannedUser);
|
||||
_bannedUsers.RemoveAll(b => string.Equals(b.UID, bannedUser.UID, StringComparison.Ordinal));
|
||||
}
|
||||
UiSharedService.AttachToolTip("Unban");
|
||||
|
||||
ImGui.SameLine(0f, style.ItemSpacing.X);
|
||||
|
||||
if (!isEditing)
|
||||
{
|
||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Edit))
|
||||
{
|
||||
_banEditError = null;
|
||||
_editingBanUid = bannedUser.UID;
|
||||
_banReasonEdits[bannedUser.UID] = StripAliasSuffix(bannedUser.Reason ?? string.Empty);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Edit reason");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Save))
|
||||
{
|
||||
_banEditError = null;
|
||||
_banEditTask = SaveBanReasonViaBanUserAsync(bannedUser.UID);
|
||||
}
|
||||
UiSharedService.AttachToolTip("Save");
|
||||
|
||||
ImGui.SameLine(0f, style.ItemSpacing.X);
|
||||
|
||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Times))
|
||||
{
|
||||
_banEditError = null;
|
||||
_editingBanUid = null;
|
||||
}
|
||||
UiSharedService.AttachToolTip("Cancel");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawInvites(GroupPermissions perm)
|
||||
{
|
||||
var inviteTab = ImRaii.TabItem("Invites");
|
||||
@@ -902,7 +1235,9 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
if (buttonCount == 0)
|
||||
return;
|
||||
|
||||
float totalWidth = buttonCount * frameH + (buttonCount - 1) * style.ItemSpacing.X;
|
||||
float totalWidth = _isOwner
|
||||
? buttonCount * frameH + buttonCount * style.ItemSpacing.X + 20f
|
||||
: buttonCount * frameH + buttonCount * style.ItemSpacing.X;
|
||||
|
||||
float curX = ImGui.GetCursorPosX();
|
||||
float avail = ImGui.GetContentRegionAvail().X;
|
||||
@@ -1031,69 +1366,40 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
UiSharedService.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.0f);
|
||||
}
|
||||
|
||||
private void DrawBannedRow(BannedGroupUserDto bannedUser, int rowIndex, float colIdentity, float colMeta, float colActions)
|
||||
private void QueueBanListRefresh(bool force = false)
|
||||
{
|
||||
using var id = ImRaii.PushId("banRow_" + bannedUser.UID);
|
||||
|
||||
var style = ImGui.GetStyle();
|
||||
float x0 = ImGui.GetCursorPosX();
|
||||
|
||||
if (rowIndex % 2 == 0)
|
||||
if (!force)
|
||||
{
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
var pMin = ImGui.GetCursorScreenPos();
|
||||
var rowHeight = ImGui.GetTextLineHeightWithSpacing() * 2.6f;
|
||||
var pMax = new Vector2(
|
||||
pMin.X + colIdentity + colMeta + colActions + style.ItemSpacing.X * 2.0f,
|
||||
pMin.Y + rowHeight);
|
||||
|
||||
var bgColor = UIColors.Get("FullBlack").WithAlpha(0.10f);
|
||||
drawList.AddRectFilled(pMin, pMax, ImGui.ColorConvertFloat4ToU32(bgColor));
|
||||
if (_bannedUsersTask != null && !_bannedUsersTask.IsCompleted)
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosX(x0);
|
||||
ImGui.AlignTextToFramePadding();
|
||||
_bannedUsersLoaded = false;
|
||||
_bannedUsersLoadError = null;
|
||||
|
||||
string alias = bannedUser.UserAlias ?? string.Empty;
|
||||
string line1 = string.IsNullOrEmpty(alias)
|
||||
? bannedUser.UID
|
||||
: $"{alias} ({bannedUser.UID})";
|
||||
_bannedUsersTask = _apiController.GroupGetBannedUsers(new GroupDto(GroupFullInfo.Group));
|
||||
}
|
||||
|
||||
ImGui.TextUnformatted(line1);
|
||||
private void EnsureBanListLoaded()
|
||||
{
|
||||
_bannedUsersTask ??= _apiController.GroupGetBannedUsers(new GroupDto(GroupFullInfo.Group));
|
||||
|
||||
var reason = bannedUser.Reason ?? string.Empty;
|
||||
if (!string.IsNullOrWhiteSpace(reason))
|
||||
if (_bannedUsersLoaded || _bannedUsersTask == null)
|
||||
return;
|
||||
|
||||
if (!_bannedUsersTask.IsCompleted)
|
||||
return;
|
||||
|
||||
if (_bannedUsersTask.IsFaulted || _bannedUsersTask.IsCanceled)
|
||||
{
|
||||
var reasonPos = new Vector2(x0, ImGui.GetCursorPosY());
|
||||
ImGui.SetCursorPos(reasonPos);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||
UiSharedService.TextWrapped(reason);
|
||||
ImGui.PopStyleColor();
|
||||
_bannedUsersLoadError = "Failed to load banlist from server.";
|
||||
_bannedUsers = [];
|
||||
_bannedUsersLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(x0 + colIdentity + style.ItemSpacing.X);
|
||||
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted($"By: {bannedUser.BannedBy}");
|
||||
|
||||
var dateText = bannedUser.BannedOn.ToLocalTime().ToString(CultureInfo.CurrentCulture);
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
|
||||
ImGui.TextUnformatted(dateText);
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(x0 + colIdentity + colMeta + style.ItemSpacing.X * 2.0f);
|
||||
|
||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Check, "Unban"))
|
||||
{
|
||||
_apiController.GroupUnbanUser(bannedUser);
|
||||
_bannedUsers.RemoveAll(b => string.Equals(b.UID, bannedUser.UID, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
UiSharedService.AttachToolTip($"Unban {alias} ({bannedUser.UID}) from this Syncshell");
|
||||
|
||||
ImGui.Dummy(new Vector2(0, 4 * ImGuiHelpers.GlobalScale));
|
||||
_bannedUsers = _bannedUsersTask.GetAwaiter().GetResult() ?? [];
|
||||
_bannedUsersLoaded = true;
|
||||
}
|
||||
|
||||
private void SavePruneSettings()
|
||||
@@ -1116,6 +1422,13 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
}
|
||||
}
|
||||
|
||||
private static string StripAliasSuffix(string reason)
|
||||
{
|
||||
const string marker = " (Alias at time of ban:";
|
||||
var idx = reason.IndexOf(marker, StringComparison.Ordinal);
|
||||
return idx >= 0 ? reason[..idx] : reason;
|
||||
}
|
||||
|
||||
private static bool MatchesUserFilter(Pair pair, string filterLower)
|
||||
{
|
||||
var note = pair.GetNote() ?? string.Empty;
|
||||
@@ -1127,6 +1440,11 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase
|
||||
|| alias.Contains(filterLower, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override void OnOpen()
|
||||
{
|
||||
base.OnOpen();
|
||||
QueueBanListRefresh(force: true);
|
||||
}
|
||||
public override void OnClose()
|
||||
{
|
||||
Mediator.Publish(new RemoveWindowMessage(this));
|
||||
|
||||
Reference in New Issue
Block a user