feat: release v0.2.3 with moderation system, private channels, and UI enhancements

This commit is contained in:
HueByte
2026-02-19 19:37:45 +01:00
parent 38b60e5626
commit 0dbb02d12a
6 changed files with 64 additions and 6 deletions
+1
View File
@@ -4,6 +4,7 @@ Release history for EchoHub.
## Releases ## Releases
- [v0.2.3](v0.2.3.md) - Moderation, Private Channels & UI Overhaul
- [v0.2.2](v0.2.2.md) - Startup & Shutdown Fixes - [v0.2.2](v0.2.2.md) - Startup & Shutdown Fixes
- [v0.2.1](v0.2.1.md) - Shutdown & CI Fixes - [v0.2.1](v0.2.1.md) - Shutdown & CI Fixes
- [v0.2.0](v0.2.0.md) - IRC Gateway - [v0.2.0](v0.2.0.md) - IRC Gateway
+2
View File
@@ -1,5 +1,7 @@
- name: Overview - name: Overview
href: index.md href: index.md
- name: v0.2.3
href: v0.2.3.md
- name: v0.2.2 - name: v0.2.2
href: v0.2.2.md href: v0.2.2.md
- name: v0.2.1 - name: v0.2.1
+55
View File
@@ -0,0 +1,55 @@
# v0.2.3 - Moderation, Private Channels & UI Overhaul
## Features
### Moderation System
- Added server roles: Owner, Admin, Mod, Member — first registered user is automatically Owner
- New `/kick`, `/ban`, `/unban`, `/mute`, `/unmute`, `/role`, `/nuke` commands for moderators and admins
- `ModerationController` with full REST API for role assignment, kicks, bans, mutes, message deletion, and channel nuking
- Mutes support optional duration (auto-expire) and blocked users cannot log in
- Role claim included in JWT tokens; role badges shown in the online users panel
### Private Channels
- Channels can be created as public or private via a checkbox in the Create Channel dialog
- Public channels are visible to all users; private channels only appear for members who joined them
- Persistent channel membership tracked in the database (`ChannelMembership` table)
- `GET /api/channels` returns the combined list: public channels + user's joined private channels
- Channel creators are automatically added as members
### Online Users Panel
- Collapsible right-side panel showing online users in the current channel (toggle with F2)
- Users displayed with status indicators, role badges, and their custom nickname colors
- Panel updates on join, leave, and status change events
### @mention Highlighting
- `@username` text rendered in orange accent color in all messages
- Messages mentioning the current user get a full-line amber background highlight
- Works across multi-line messages and continuation lines
### ASCII Art Improvements
- Half-block character rendering (`▀`/`█`) with separate foreground + background colors for 2x vertical resolution
- Switched from ANSI escape codes to printable color tags (`{F:RRGGBB}`, `{B:RRGGBB}`, `{X}`) — no control bytes in stored content
- Optional size parameter for `/send` command: `-s` (40x40), `-m` (80x80, default), `-l` (120x120)
- IRC gateway converts color tags back to ANSI for IRC client compatibility
### Client UI
- Version number shown in the status bar
- Custom colored rendering for channel list (active indicator, unread count badges)
- Avatar upload field added to the profile edit dialog (file path or URL)
- Update check notification on connect — shows a system message if a newer GitHub release exists
- Chat messages no longer show selection/focus highlight
- Exit shortcut changed from Ctrl+C to Alt+Q — frees Ctrl+C for copy
- Default history increased from 50 to 100 messages on channel join
## Fixes
- Fixed `#general` channel not visible after adding the `IsPublic` column — migration default changed to `true` and startup service ensures it
- Fixed channels disappearing when creating a new channel — replaced full re-fetch with incremental updates
- Wired `OnChannelUpdated` SignalR event so new public channels appear for all connected users in real time
- Fixed color tag parser using wrong regex group numbers (6,7,8 instead of 1,2,3) — new ASCII art was rendering without colors
## Infrastructure
- Startup `DataMigrationService` automatically converts old ANSI-format messages to the new color tag format on server boot, logging the count of migrated records
- Three new EF Core migrations: `AddModerationRoles`, `AddChannelIsPublic`, `AddChannelMembership`
- `ChannelMembership` table with cascade delete on both channel and user removal
+1 -1
View File
@@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>0.2.2</Version> <Version>0.2.3</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn> <NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup> </PropertyGroup>
+4 -4
View File
@@ -40,7 +40,7 @@ public sealed class MainWindow : Runnable
// Cached Key constants — compare via .KeyCode to avoid Key.Equals (which also checks Handled) // Cached Key constants — compare via .KeyCode to avoid Key.Equals (which also checks Handled)
private static readonly Key EnterKey = Key.Enter; private static readonly Key EnterKey = Key.Enter;
private static readonly Key NewlineKey = Key.N.WithCtrl; private static readonly Key NewlineKey = Key.N.WithCtrl;
private static readonly Key CtrlCKey = Key.C.WithCtrl; private static readonly Key AltQKey = Key.Q.WithAlt;
private static readonly Key TabKey = Key.Tab; private static readonly Key TabKey = Key.Tab;
// Available slash commands for Tab autocomplete // Available slash commands for Tab autocomplete
@@ -240,7 +240,7 @@ public sealed class MainWindow : Runnable
_messageList.ViewportChanged += (_, _) => OnChatViewportChanged(); _messageList.ViewportChanged += (_, _) => OnChatViewportChanged();
_chatFrame.ViewportChanged += (_, _) => OnChatViewportChanged(); _chatFrame.ViewportChanged += (_, _) => OnChatViewportChanged();
// Window-level key handling for Ctrl+C (quit), F2 (toggle users panel) // Window-level key handling for Alt+Q (quit), F2 (toggle users panel)
KeyDown += OnWindowKeyDown; KeyDown += OnWindowKeyDown;
} }
@@ -379,7 +379,7 @@ public sealed class MainWindow : Runnable
} }
e.Handled = true; e.Handled = true;
} }
else if (e.KeyCode == CtrlCKey.KeyCode) else if (e.KeyCode == AltQKey.KeyCode)
{ {
_app.RequestStop(); _app.RequestStop();
e.Handled = true; e.Handled = true;
@@ -432,7 +432,7 @@ public sealed class MainWindow : Runnable
private void OnWindowKeyDown(object? sender, Key e) private void OnWindowKeyDown(object? sender, Key e)
{ {
if (e.KeyCode == CtrlCKey.KeyCode) if (e.KeyCode == AltQKey.KeyCode)
{ {
_app.RequestStop(); _app.RequestStop();
e.Handled = true; e.Handled = true;
+1 -1
View File
@@ -4,7 +4,7 @@ public static class HubConstants
{ {
public const string ChatHubPath = "/hubs/chat"; public const string ChatHubPath = "/hubs/chat";
public const string DefaultChannel = "general"; public const string DefaultChannel = "general";
public const int DefaultHistoryCount = 50; public const int DefaultHistoryCount = 100;
public const int MaxMessageLength = 2000; public const int MaxMessageLength = 2000;
public const int MaxFileSizeBytes = 10 * 1024 * 1024; // 10 MB public const int MaxFileSizeBytes = 10 * 1024 * 1024; // 10 MB
public const int MaxAvatarSizeBytes = 2 * 1024 * 1024; // 2 MB public const int MaxAvatarSizeBytes = 2 * 1024 * 1024; // 2 MB