From c69e5c790b2b277d9b11265b8f0883e9f90fe3b9 Mon Sep 17 00:00:00 2001 From: Rory& Date: Fri, 22 Mar 2024 17:47:29 +0100 Subject: Changes --- MatrixUtils.Web/Pages/Index.razor | 32 ++++++- MatrixUtils.Web/Pages/Rooms/Index.razor | 10 +-- MatrixUtils.Web/Pages/Rooms/Index2.razor | 2 + .../RoomsIndex2ByRoomTypeTab.razor | 53 ++++++++++++ .../RoomsIndex2SyncContainer.razor | 1 - MatrixUtils.Web/Pages/Rooms/Timeline.razor | 44 +++++----- MatrixUtils.Web/Pages/Tools/InviteCounter.razor | 73 ++++++++++++++++ MatrixUtils.Web/Pages/Tools/MassCMEBan.razor | 75 +++++++++++++++++ MatrixUtils.Web/Pages/Tools/UserTrace.razor | 97 +++++++++++----------- MatrixUtils.Web/Shared/MainLayout.razor | 8 +- MatrixUtils.Web/Shared/ResourceUsage.razor | 64 ++++++++++++++ MatrixUtils.Web/Shared/RoomListItem.razor | 2 +- .../TimelineComponents/BaseTimelineItem.razor | 4 +- .../TimelineUnknownStateItem.razor | 16 ++++ 14 files changed, 402 insertions(+), 79 deletions(-) create mode 100644 MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2ByRoomTypeTab.razor create mode 100644 MatrixUtils.Web/Pages/Tools/InviteCounter.razor create mode 100644 MatrixUtils.Web/Pages/Tools/MassCMEBan.razor create mode 100644 MatrixUtils.Web/Shared/ResourceUsage.razor create mode 100644 MatrixUtils.Web/Shared/TimelineComponents/TimelineUnknownStateItem.razor (limited to 'MatrixUtils.Web') diff --git a/MatrixUtils.Web/Pages/Index.razor b/MatrixUtils.Web/Pages/Index.razor index 19c74c3..7c0a9f2 100644 --- a/MatrixUtils.Web/Pages/Index.razor +++ b/MatrixUtils.Web/Pages/Index.razor @@ -88,6 +88,35 @@ Small collection of tools to do not-so-everyday things. } +@if (_invalidSessions.Count > 0) { +
+
+
Invalid sessions
+
+
+ + @foreach (var session in _invalidSessions) { + + + + + } +
+

+ @{ + string[] parts = session.UserId.Split(':'); + } + @parts[0][1..] on @parts[1] + @if (!string.IsNullOrWhiteSpace(session.Proxy)) { + (proxied via @session.Proxy) + } +

+
+ Remove +
+
+} + @code { #if DEBUG @@ -106,6 +135,7 @@ Small collection of tools to do not-so-everyday things. // private Dictionary _users = new(); private readonly List _sessions = []; private readonly List _offlineSessions = []; + private readonly List _invalidSessions = []; private LoginResponse? _currentSession; int scannedSessions = 0, totalSessions = 1; private SvgIdenticonGenerator _identiconGenerator = new(); @@ -162,7 +192,7 @@ Small collection of tools to do not-so-everyday things. } } catch (MatrixException e) { - if (e is { ErrorCode: "M_UNKNOWN_TOKEN" }) _offlineSessions.Add(token); + if (e is { ErrorCode: "M_UNKNOWN_TOKEN" }) _invalidSessions.Add(token); else throw; } catch { diff --git a/MatrixUtils.Web/Pages/Rooms/Index.razor b/MatrixUtils.Web/Pages/Rooms/Index.razor index c44e23f..28c4de2 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixUtils.Web/Pages/Rooms/Index.razor @@ -13,8 +13,9 @@

@Status2

Create new room - - + + + @code { @@ -73,10 +74,9 @@ // SemaphoreSlim _semaphore = new(160, 160); GlobalProfile = await Homeserver.GetProfileAsync(Homeserver.WhoAmI.UserId); - // var filter = await Homeserver.NamedCaches.FilterCache.GetOrSetValueAsync(CommonSyncFilters.GetBasicRoomInfo); var filter = await Homeserver.NamedCaches.FilterCache.GetOrSetValueAsync(CommonSyncFilters.GetBasicRoomInfo); var filterData = await Homeserver.GetFilterAsync(filter); - + // Rooms = new ObservableCollection(rooms.Select(room => new RoomInfo(room))); // foreach (var stateType in filterData.Room?.State?.Types ?? []) { // var tasks = Rooms.Select(async room => { @@ -204,7 +204,7 @@ if (sync is null) continue; var filter = await Homeserver.GetFilterAsync(syncHelper.FilterId); - + Status = $"Got sync with {sync.Rooms?.Join?.Count ?? 0} room updates, next batch: {sync.NextBatch}!"; if (sync?.Rooms?.Join != null) foreach (var joinedRoom in sync.Rooms.Join) diff --git a/MatrixUtils.Web/Pages/Rooms/Index2.razor b/MatrixUtils.Web/Pages/Rooms/Index2.razor index ae31126..98b8a1d 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index2.razor +++ b/MatrixUtils.Web/Pages/Rooms/Index2.razor @@ -27,9 +27,11 @@ break; case Tab.DMs:

DMs tab

+ break; case Tab.ByRoomType:

By room type tab

+ break; default: throw new InvalidEnumArgumentException(); diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2ByRoomTypeTab.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2ByRoomTypeTab.razor new file mode 100644 index 0000000..f4cf849 --- /dev/null +++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2ByRoomTypeTab.razor @@ -0,0 +1,53 @@ +@using MatrixUtils.Abstractions +@using System.Security.Cryptography +@using ArcaneLibs.Extensions +

RoomsIndex2MainTab

+ +
+
+
+ Uncategorised rooms + @foreach (var space in Data.Rooms.Where(x => x.RoomType == "m.space")) { +
+

@space.RoomName

+
+ } +
+
+

omae wa mou shindeiru

+
+
+
+ +@code { + + [CascadingParameter] + public Index2.RoomListViewData Data { get; set; } = null!; + + protected override async Task OnInitializedAsync() { + Data.Rooms.CollectionChanged += (sender, args) => { + DebouncedStateHasChanged(); + if (args.NewItems is { Count: > 0 }) + foreach (var newItem in args.NewItems) { + (newItem as RoomInfo).PropertyChanged += (sender, args) => { DebouncedStateHasChanged(); }; + } + }; + await base.OnInitializedAsync(); + } + + //debounce StateHasChanged, we dont want to reredner on every key stroke + + private CancellationTokenSource _debounceCts = new CancellationTokenSource(); + + private async Task DebouncedStateHasChanged() { + _debounceCts.Cancel(); + _debounceCts = new CancellationTokenSource(); + try { + await Task.Delay(100, _debounceCts.Token); + Console.WriteLine("DebouncedStateHasChanged - Calling StateHasChanged!"); + StateHasChanged(); + } + catch (TaskCanceledException) { } + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor index 1fb3f89..418ee02 100644 --- a/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor +++ b/MatrixUtils.Web/Pages/Rooms/Index2Components/RoomsIndex2SyncContainer.razor @@ -50,7 +50,6 @@ ["Main"] = new SyncHelper(Data.Homeserver, logger) { Timeout = 30000, FilterId = await Data.Homeserver.NamedCaches.FilterCache.GetOrSetValueAsync(CommonSyncFilters.GetBasicRoomInfo), - // FilterId = await Data.Homeserver.NamedCaches.FilterCache.GetOrSetValueAsync(CommonSyncFilters.GetBasicRoomInfo), // MinimumDelay = TimeSpan.FromMilliseconds(5000) } }; diff --git a/MatrixUtils.Web/Pages/Rooms/Timeline.razor b/MatrixUtils.Web/Pages/Rooms/Timeline.razor index 3886c5b..e6b1248 100644 --- a/MatrixUtils.Web/Pages/Rooms/Timeline.razor +++ b/MatrixUtils.Web/Pages/Rooms/Timeline.razor @@ -8,9 +8,9 @@

Loaded @Events.Count events...

@foreach (var evt in Events) { -
- +
+
} @@ -20,8 +20,8 @@ [Parameter] public string RoomId { get; set; } - private List Messages { get; } = new(); - private List Events { get; } = new(); + private List Events { get; } = new(); + private List RawEvents { get; } = new(); private AuthenticatedHomeserverGeneric? Homeserver { get; set; } @@ -32,28 +32,34 @@ var room = Homeserver.GetRoom(RoomId); MessagesResponse? msgs = null; do { - msgs = await room.GetMessagesAsync(limit: 1000, from: msgs?.End, dir: "b"); - Messages.Add(msgs); + msgs = await room.GetMessagesAsync(limit: 10000, from: msgs?.End, dir: "b"); Console.WriteLine($"Got {msgs.Chunk.Count} messages"); + StateHasChanged(); msgs.Chunk.Reverse(); - Events.InsertRange(0, msgs.Chunk); + Events.InsertRange(0, msgs.Chunk.Select(x => new TimelineEventItem { Event = x, Type = ComponentType(x) })); + RawEvents.InsertRange(0, msgs.Chunk); } while (msgs.End is not null); - await base.OnInitializedAsync(); } - private StateEventResponse GetProfileEventBefore(StateEventResponse Event) => Events.TakeWhile(x => x != Event).Last(e => e.Type == "m.room.member" && e.StateKey == Event.Sender); + // private StateEventResponse GetProfileEventBefore(StateEventResponse Event) => Events.TakeWhile(x => x != Event).Last(e => e.Type == RoomMemberEventContent.EventId && e.StateKey == Event.Sender); - private Type ComponentType(StateEvent Event) => Event.TypedContent switch { - RoomCanonicalAliasEventContent => typeof(TimelineCanonicalAliasItem), - RoomHistoryVisibilityEventContent => typeof(TimelineHistoryVisibilityItem), - RoomTopicEventContent => typeof(TimelineRoomTopicItem), - RoomMemberEventContent => typeof(TimelineMemberItem), - RoomMessageEventContent => typeof(TimelineMessageItem), - RoomCreateEventContent => typeof(TimelineRoomCreateItem), - RoomNameEventContent => typeof(TimelineRoomNameItem), + private Type ComponentType(StateEvent Event) => Event.Type switch { + RoomCanonicalAliasEventContent.EventId => typeof(TimelineCanonicalAliasItem), + RoomHistoryVisibilityEventContent.EventId => typeof(TimelineHistoryVisibilityItem), + RoomTopicEventContent.EventId => typeof(TimelineRoomTopicItem), + RoomMemberEventContent.EventId => typeof(TimelineMemberItem), + RoomMessageEventContent.EventId => typeof(TimelineMessageItem), + RoomCreateEventContent.EventId => typeof(TimelineRoomCreateItem), + RoomNameEventContent.EventId => typeof(TimelineRoomNameItem), + // RoomMessageReactionEventContent.EventId => typeof(ComponentBase), _ => typeof(TimelineUnknownItem) }; + + private class TimelineEventItem : ComponentBase { + public StateEventResponse Event { get; set; } + public Type Type { get; set; } + } -} +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/InviteCounter.razor b/MatrixUtils.Web/Pages/Tools/InviteCounter.razor new file mode 100644 index 0000000..8f4b4dd --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/InviteCounter.razor @@ -0,0 +1,73 @@ +@page "/Tools/InviteCounter" +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +@using System.Collections.ObjectModel +@using LibMatrix +@using System.Collections.Frozen +@using LibMatrix.EventTypes.Spec.State +@using MatrixUtils.Abstractions +

User Trace

+
+ +
+Room ID: + +Execute + +
+ +
+ Results + @foreach (var (userId, events) in invites.OrderByDescending(x=>x.Value).ToList()) { +

@userId: @events

+ } +
+ +
+@foreach (var line in log.Reverse()) { +
@line
+} + +@code { + private ObservableCollection log { get; set; } = new(); + private Dictionary invites { get; set; } = new(); + private AuthenticatedHomeserverGeneric hs { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "room")] + public string roomId { get; set; } + + + protected override async Task OnInitializedAsync() { + log.CollectionChanged += (sender, args) => StateHasChanged(); + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + var room = hs.GetRoom(roomId); + var events = room.GetManyMessagesAsync(limit: int.MaxValue); + await foreach (var resp in events) { + var all = resp.State.Concat(resp.Chunk); + foreach (var evt in all) { + if(evt.Type != RoomMemberEventContent.EventId) continue; + var content = evt.TypedContent as RoomMemberEventContent; + if(content.Membership != "invite") continue; + if(!invites.ContainsKey(evt.Sender)) invites[evt.Sender] = 0; + invites[evt.Sender]++; + } + + log.Add($"{resp.State.Count} state, {resp.Chunk.Count} timeline"); + } + + + + StateHasChanged(); + + return ""; + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor b/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor new file mode 100644 index 0000000..cbbca9e --- /dev/null +++ b/MatrixUtils.Web/Pages/Tools/MassCMEBan.razor @@ -0,0 +1,75 @@ +@page "/Tools/MassCMEBan" +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +@using System.Collections.ObjectModel +@using LibMatrix +@using System.Collections.Frozen +@using LibMatrix.EventTypes.Spec.State +@using LibMatrix.EventTypes.Spec.State.Policy +@using MatrixUtils.Abstractions +

User Trace

+
+ +
+Users: + +Execute + +
+ +
+@foreach (var line in log.Reverse()) { +
@line
+} + +@code { + // TODO: Properly implement page to be more useful + private ObservableCollection log { get; set; } = new(); + private AuthenticatedHomeserverGeneric hs { get; set; } + + [Parameter, SupplyParameterFromQuery(Name = "room")] + public string roomId { get; set; } + + + protected override async Task OnInitializedAsync() { + log.CollectionChanged += (sender, args) => StateHasChanged(); + hs = await RMUStorage.GetCurrentSessionOrNavigate(); + if (hs is null) return; + + StateHasChanged(); + Console.WriteLine("Rerendered!"); + await base.OnInitializedAsync(); + } + + private async Task Execute() { + var room = hs.GetRoom("!fTjMjIzNKEsFlUIiru:neko.dev"); + // var room = hs.GetRoom("!yf7OpOiRDXx6zUGpT6:conduit.rory.gay"); + var users = roomId.Split("\n").Select(x => x.Trim()).Where(x=>x.StartsWith('@')).ToList(); + foreach (var user in users) { + var exists = false; + try { + exists = !string.IsNullOrWhiteSpace((await room.GetStateAsync(UserPolicyRuleEventContent.EventId, user.Replace('@', '_'))).Entity); + } catch (Exception e) { + log.Add($"Failed to get {user}"); + } + + if (!exists) { + var evt = await room.SendStateEventAsync(UserPolicyRuleEventContent.EventId, user.Replace('@', '_'), new UserPolicyRuleEventContent() { + Entity = user, + Reason = "spam (invite)", + Recommendation = "m.ban" + }); + log.Add($"Sent {evt.EventId} to ban {user}"); + } + else { + log.Add($"User {user} already exists"); + } + } + + + StateHasChanged(); + + return ""; + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Tools/UserTrace.razor b/MatrixUtils.Web/Pages/Tools/UserTrace.razor index d78c58a..4ad9874 100644 --- a/MatrixUtils.Web/Pages/Tools/UserTrace.razor +++ b/MatrixUtils.Web/Pages/Tools/UserTrace.razor @@ -5,6 +5,7 @@ @using LibMatrix @using System.Collections.Frozen @using LibMatrix.EventTypes.Spec.State +@using MatrixUtils.Abstractions

User Trace


@@ -16,7 +17,7 @@
Rooms to be searched (@rooms.Count) @foreach (var room in rooms) { - @room.RoomId + @room.Room.RoomId
}
@@ -29,8 +30,13 @@ @foreach (var (userId, events) in matches) {

@userId

    - @foreach (var eventResponse in events) { -
  • @eventResponse.Room.RoomId
  • + @foreach (var match in events) { +
  • +
      +
    • @match.RoomName (@match.Room.RoomId)
    • +
    • Membership: @(match.Event.RawContent.ToJson(indent: false))
    • +
    +
  • }
} @@ -43,10 +49,8 @@ @code { private ObservableCollection log { get; set; } = new(); - List hss { get; set; } = new(); - ObservableCollection rooms { get; set; } = new(); - Dictionary> roomMembers { get; set; } = new(); - Dictionary> matches = new(); + List rooms { get; set; } = new(); + Dictionary> matches = new(); private string UserIdString { get => string.Join("\n", UserIDs); @@ -59,16 +63,13 @@ log.CollectionChanged += (sender, args) => StateHasChanged(); var hs = await RMUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; - rooms.CollectionChanged += (sender, args) => StateHasChanged(); var sessions = await RMUStorage.GetAllTokens(); + var baseRooms = new List(); foreach (var userAuth in sessions) { var session = await RMUStorage.GetSession(userAuth); if (session is not null) { - var sessionRooms = await session.GetJoinedRooms(); - foreach (var room in sessionRooms) { - rooms.Add(room); - } - + baseRooms.AddRange(await session.GetJoinedRooms()); + var sessionRooms = (await session.GetJoinedRooms()).Where(x => !rooms.Any(y => y.Room.RoomId == x.RoomId)).ToList(); StateHasChanged(); log.Add($"Got {sessionRooms.Count} rooms for {userAuth.UserId}"); } @@ -76,32 +77,28 @@ log.Add("Done fetching rooms!"); - var distinctRooms = rooms.DistinctBy(x => x.RoomId).ToArray(); - Random.Shared.Shuffle(distinctRooms); - rooms = new ObservableCollection(distinctRooms); - rooms.CollectionChanged += (sender, args) => StateHasChanged(); - try { - var stateTasks = rooms.Select(async x => { - for (int i = 0; i < 10; i++) { - try { - return (x, await x.GetMembersListAsync(false)); - } - catch { - // - } + baseRooms = baseRooms.DistinctBy(x => x.RoomId).ToList(); + + // rooms.CollectionChanged += (sender, args) => StateHasChanged(); + var tasks = baseRooms.Select(async newRoom => { + bool success = false; + while (!success) + try { + var state = await newRoom.GetFullStateAsListAsync(); + var newRoomInfo = new RoomInfo(newRoom, state); + rooms.Add(newRoomInfo); + log.Add($"Got {newRoomInfo.StateEvents.Count} events for {newRoomInfo.RoomName}"); + success = true; } - - return (x, new List().ToFrozenSet()); - }).ToAsyncEnumerable(); - - await foreach (var (room, state) in stateTasks) { - roomMembers.Add(room, state); - log.Add($"Got {state.Count} members for {room.RoomId}..."); - } - } - catch { - // - } + catch (MatrixException e) { + log.Add($"Failed to fetch room {newRoom.RoomId}! {e}"); + throw; + } + catch (HttpRequestException e) { + log.Add($"Failed to fetch room {newRoom.RoomId}! {e}"); + } + }); + await Task.WhenAll(tasks); log.Add($"Done fetching members!"); @@ -114,17 +111,22 @@ private async Task Execute() { foreach (var userId in UserIDs) { - matches.Add(userId, new List()); - foreach (var (room, events) in roomMembers) { - if (events.Any(x => x.Type == RoomMemberEventContent.EventId && x.StateKey == userId)) { + matches.Add(userId, new List()); + + foreach (var room in rooms) { + var state = room.StateEvents.Where(x => x!.Type == RoomMemberEventContent.EventId).ToList(); + if (state!.Any(x => x.StateKey == userId)) { matches[userId].Add(new() { - Event = events.First(x => x.StateKey == userId && x.Type == RoomMemberEventContent.EventId), - Room = room, + Event = state.First(x => x.StateKey == userId), + Room = room.Room, + RoomName = room.RoomName ?? "No name" }); } } } + StateHasChanged(); + return ""; } @@ -133,8 +135,8 @@ private async Task DoImportFromRoomId() { try { if (ImportFromRoomId is null) return; - var room = rooms.FirstOrDefault(x => x.RoomId == ImportFromRoomId); - UserIdString = string.Join("\n", (await room.GetMembersListAsync()).Select(x => x.StateKey)); + var room = rooms.FirstOrDefault(x => x.Room.RoomId == ImportFromRoomId); + UserIdString = string.Join("\n", (await room.Room.GetMembersListAsync()).Select(x => x.StateKey)); } catch (Exception e) { Console.WriteLine(e); @@ -144,11 +146,10 @@ StateHasChanged(); } - private class Matches { + private class Match { public GenericRoom Room; - public StateEventResponse Event; - // public + public string RoomName { get; set; } } } \ No newline at end of file diff --git a/MatrixUtils.Web/Shared/MainLayout.razor b/MatrixUtils.Web/Shared/MainLayout.razor index 41c3d69..c67f73c 100644 --- a/MatrixUtils.Web/Shared/MainLayout.razor +++ b/MatrixUtils.Web/Shared/MainLayout.razor @@ -1,4 +1,5 @@ -@inherits LayoutComponentBase +@using ArcaneLibs +@inherits LayoutComponentBase
diff --git a/MatrixUtils.Web/Shared/ResourceUsage.razor b/MatrixUtils.Web/Shared/ResourceUsage.razor new file mode 100644 index 0000000..2a6365f --- /dev/null +++ b/MatrixUtils.Web/Shared/ResourceUsage.razor @@ -0,0 +1,64 @@ +@using ArcaneLibs +@using System.Diagnostics +

ResourceUsage

+ +
+ Memory usage: @lastMemoryUsage +
+ +
+ +
+ Time jitter: @lastCpuJitter +
+ +
+
+ +@code { + private Dictionary MemoryUsage = new(); + private Dictionary CpuUsage = new(); + private string lastMemoryUsage = ""; + private string lastCpuJitter = ""; + + protected override async Task OnInitializedAsync() { + Task.Run(async () => { + try { + while (true) { + lastMemoryUsage = Util.BytesToString((long)(MemoryUsage[DateTime.Now] = GC.GetTotalMemory(false))); + if (MemoryUsage.Count > 60) + MemoryUsage.Remove(MemoryUsage.Keys.First()); + await Task.Delay(1000); + } + } + catch (Exception e) { + Console.WriteLine(e); + } + }); + + // calculate cpu usage estimate without Process or PerformanceCounter + Task.Run(async () => { + try { + var sw = new Stopwatch(); + while (true) { + sw.Restart(); + await Task.Delay(1000); + sw.Stop(); + // CpuUsage[DateTime.Now] = sw.ElapsedTicks - TimeSpan.TicksPerSecond; + var usage = sw.Elapsed - TimeSpan.FromSeconds(1); + CpuUsage[DateTime.Now] = usage.Ticks - TimeSpan.TicksPerSecond; + lastCpuJitter = usage.ToString(); + if (CpuUsage.Count > 60) + CpuUsage.Remove(MemoryUsage.Keys.First()); + StateHasChanged(); + } + } + catch (Exception e) { + Console.WriteLine(e); + } + }); + + await base.OnInitializedAsync(); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Shared/RoomListItem.razor b/MatrixUtils.Web/Shared/RoomListItem.razor index 623a03a..5a33b65 100644 --- a/MatrixUtils.Web/Shared/RoomListItem.razor +++ b/MatrixUtils.Web/Shared/RoomListItem.razor @@ -11,7 +11,7 @@
@if (OwnMemberState != null) { @* Class="@("avatar32" + (OwnMemberState?.AvatarUrl != GlobalProfile?.AvatarUrl ? " highlightChange" : "") + (ChildContent is not null ? " vcenter" : ""))" *@ - + @(OwnMemberState?.DisplayName ?? GlobalProfile?.DisplayName ?? "Loading...") diff --git a/MatrixUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor b/MatrixUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor index c7bfd51..08aeffe 100644 --- a/MatrixUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor +++ b/MatrixUtils.Web/Shared/TimelineComponents/BaseTimelineItem.razor @@ -14,9 +14,9 @@ [Parameter] public AuthenticatedHomeserverGeneric Homeserver { get; set; } - public List EventsBefore => Events.TakeWhile(e => e.EventId != Event.EventId).ToList(); + public IEnumerable EventsBefore => Events.TakeWhile(e => e.EventId != Event.EventId); - public List MatchingEventsBefore => EventsBefore.Where(x => x.Type == Event.Type && x.StateKey == Event.StateKey).ToList(); + public IEnumerable MatchingEventsBefore => EventsBefore.Where(x => x.Type == Event.Type && x.StateKey == Event.StateKey); public StateEventResponse? PreviousState => MatchingEventsBefore.LastOrDefault(); diff --git a/MatrixUtils.Web/Shared/TimelineComponents/TimelineUnknownStateItem.razor b/MatrixUtils.Web/Shared/TimelineComponents/TimelineUnknownStateItem.razor new file mode 100644 index 0000000..4f05b30 --- /dev/null +++ b/MatrixUtils.Web/Shared/TimelineComponents/TimelineUnknownStateItem.razor @@ -0,0 +1,16 @@ +@using ArcaneLibs.Extensions +@inherits BaseTimelineItem + +
+
+ + Unknown event type:
@Event.Type
+
+
@Event.ToJson(ignoreNull: true)
+
+
+ +@code { + + +} -- cgit 1.4.1