diff options
21 files changed, 122 insertions, 45 deletions
diff --git a/ArcaneLibs b/ArcaneLibs -Subproject fadd59b2d7303546585f1543ddbbc268068a70a +Subproject e4e36357535e1f44119a2861027a71d3f92f989 diff --git a/LibMatrix b/LibMatrix -Subproject f5447484512d726f4403f0d7725777d0a95601f +Subproject 0ad13628bb8ef899927b7b42b5357fe616ce057 diff --git a/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs b/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs index d687679..c7567ce 100644 --- a/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs +++ b/MatrixRoomUtils.Desktop/Components/RoomListEntry.axaml.cs @@ -47,7 +47,7 @@ public partial class RoomListEntry : UserControl { var hs = await svc.ServiceProvider.GetService<MRUStorageWrapper>()?.GetCurrentSessionOrPrompt()!; var hsResolver = svc.ServiceProvider.GetService<HomeserverResolverService>(); var storage = svc.ServiceProvider.GetService<TieredStorageService>()?.CacheStorageProvider; - var resolvedUrl = await hsResolver.ResolveMediaUri(hs.FullHomeServerDomain, mxcUrl); + var resolvedUrl = await hsResolver.ResolveMediaUri(hs.ServerName, mxcUrl); var storageKey = $"media/{mxcUrl.Replace("mxc://", "").Replace("/", ".")}"; try { if (!await storage.ObjectExistsAsync(storageKey)) diff --git a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs index 1fa56be..bea1ced 100644 --- a/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs +++ b/MatrixRoomUtils.Web/Classes/RoomCreationTemplates/DefaultRoomCreationTemplate.cs @@ -15,25 +15,25 @@ public class DefaultRoomCreationTemplate : IRoomCreationTemplate { InitialState = new List<StateEvent> { new() { Type = "m.room.history_visibility", - TypedContent = new HistoryVisibilityEventContent() { + TypedContent = new RoomHistoryVisibilityEventContent() { HistoryVisibility = "world_readable" } }, new() { Type = "m.room.guest_access", - TypedContent = new GuestAccessEventContent { + TypedContent = new RoomGuestAccessEventContent { GuestAccess = "can_join" } }, new() { Type = "m.room.join_rules", - TypedContent = new JoinRulesEventContent { + TypedContent = new RoomJoinRulesEventContent { JoinRule = "public" } }, new() { Type = "m.room.server_acl", - TypedContent = new ServerACLEventContent() { + TypedContent = new RoomServerACLEventContent() { Allow = new List<string>() { "*" }, Deny = new List<string>(), AllowIpLiterals = false diff --git a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj index 3c8d362..03cc9ae 100644 --- a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj +++ b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj @@ -24,4 +24,5 @@ </ItemGroup> + </Project> diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor index 845bbb9..834c373 100644 --- a/MatrixRoomUtils.Web/Pages/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Index.razor @@ -36,7 +36,7 @@ Small collection of tools to do not-so-everyday things. </td> <td> <p> - <LinkButton href="">Manage</LinkButton> + <LinkButton OnClick="@(()=>ManageUser(_auth))">Manage</LinkButton> <LinkButton OnClick="@(() => RemoveUser(_auth))">Remove</LinkButton> <LinkButton OnClick="@(() => RemoveUser(_auth, true))">Log out</LinkButton> </p> @@ -72,10 +72,7 @@ Small collection of tools to do not-so-everyday things. var profile = await hs.GetProfileAsync(hs.WhoAmI.UserId); userInfo.DisplayName = profile.DisplayName ?? hs.WhoAmI.UserId; Console.WriteLine(profile.ToJson()); - userInfo.AvatarUrl = await hsResolver.ResolveMediaUri(hs.FullHomeServerDomain, - profile.AvatarUrl - ?? "https://api.dicebear.com/6.x/identicon/svg?seed=" + hs.WhoAmI.UserId - ); + userInfo.AvatarUrl = string.IsNullOrWhiteSpace(profile.AvatarUrl) ? "https://api.dicebear.com/6.x/identicon/svg?seed=" + hs.WhoAmI.UserId : hs.ResolveMediaUri(profile.AvatarUrl); userInfo.RoomCount = (await roomCountTask).Count; _users.Add(token, userInfo); // StateHasChanged(); @@ -116,4 +113,9 @@ Small collection of tools to do not-so-everyday things. await MRUStorage.SetCurrentToken(auth); await OnInitializedAsync(); } + + private async Task ManageUser(UserAuth auth) { + await SwitchSession(auth); + NavigationManager.NavigateTo("/User/Manage"); + } } diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor index 5202c40..3225862 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor @@ -90,7 +90,7 @@ <tr> <td>Room icon:</td> <td> - <img src="@hsResolver.ResolveMediaUri(HomeServer.HomeServerDomain, roomAvatarEvent.Url)" style="width: 128px; height: 128px; border-radius: 50%;"/> + <img src="@hsResolver.ResolveMediaUri(HomeServer.ServerName, roomAvatarEvent.Url)" style="width: 128px; height: 128px; border-radius: 50%;"/> <div style="display: inline-block; vertical-align: middle;"> <FancyTextBox @bind-Value="@roomAvatarEvent.Url"></FancyTextBox><br/> <InputFile OnChange="RoomIconFilePicked"></InputFile> @@ -135,7 +135,7 @@ } else { <details> - <summary>@((creationEvent["m.room.server_acls"].TypedContent as ServerACLEventContent).Allow.Count) allow rules</summary> + <summary>@((creationEvent["m.room.server_acls"].TypedContent as RoomServerACLEventContent).Allow.Count) allow rules</summary> @* <StringListEditor @bind-Items="@serverAcl.Allow"></StringListEditor> *@ </details> } @@ -145,7 +145,7 @@ } else { <details> - <summary>@((creationEvent["m.room.server_acls"].TypedContent as ServerACLEventContent).Deny.Count) deny rules</summary> + <summary>@((creationEvent["m.room.server_acls"].TypedContent as RoomServerACLEventContent).Deny.Count) deny rules</summary> @* <StringListEditor @bind-Items="@serverAcl.Allow"></StringListEditor> *@ </details> } @@ -255,9 +255,9 @@ private MatrixException? _matrixException { get; set; } - private HistoryVisibilityEventContent? historyVisibility => creationEvent?["m.room.history_visibility"].TypedContent as HistoryVisibilityEventContent; - private GuestAccessEventContent? guestAccessEvent => creationEvent?["m.room.guest_access"].TypedContent as GuestAccessEventContent; - private ServerACLEventContent? serverAcl => creationEvent?["m.room.server_acls"].TypedContent as ServerACLEventContent; + private RoomHistoryVisibilityEventContent? historyVisibility => creationEvent?["m.room.history_visibility"].TypedContent as RoomHistoryVisibilityEventContent; + private RoomGuestAccessEventContent? guestAccessEvent => creationEvent?["m.room.guest_access"].TypedContent as RoomGuestAccessEventContent; + private RoomServerACLEventContent? serverAcl => creationEvent?["m.room.server_acls"].TypedContent as RoomServerACLEventContent; private RoomAvatarEventContent? roomAvatarEvent => creationEvent?["m.room.avatar"].TypedContent as RoomAvatarEventContent; protected override async Task OnInitializedAsync() { diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor index 99e8cbb..69a0ede 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/Index.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/Index.razor @@ -3,6 +3,7 @@ @using LibMatrix.Helpers @using LibMatrix.Responses @using LibMatrix.EventTypes.Spec.State +@using LibMatrix <h3>Room list</h3> <p>@Status</p> @@ -58,10 +59,14 @@ GlobalProfile = await hs.GetProfileAsync(hs.WhoAmI.UserId); Status = "Syncing..."; - SyncResult? sync = null; + var syncHelper = new SyncHelper(hs) { + Timeout = 0, + Filter = filter + }; + // SyncResponse? sync = null; string? nextBatch = null; - while (sync is null or { Rooms.Join.Count: >= 1}) { - sync = await hs.SyncHelper.Sync(since: nextBatch, filter: filter, timeout: 0); + var syncs = syncHelper.EnumerateSyncAsync(); + await foreach (var sync in syncs) { nextBatch = sync?.NextBatch ?? nextBatch; if (sync is null) continue; Console.WriteLine($"Got sync, next batch: {nextBatch}!"); @@ -86,7 +91,12 @@ Status = $"Got {Rooms.Count} rooms so far! Next batch: {nextBatch}"; StateHasChanged(); await Task.Delay(100); + if (!syncHelper.IsInitialSync) break; } + // while (sync is null or { Rooms.Join.Count: >= 1}) { + // sync = await syncHelper.SyncAsync(since: nextBatch, filter: filter, timeout: 0); + + // } Console.WriteLine("Sync done!"); Status = "Sync complete!"; foreach (var roomInfo in Rooms) { diff --git a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor index e6f436e..15220da 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/PolicyList.razor @@ -235,7 +235,7 @@ else { var server = servers.ContainsKey(hs) ? servers[hs] : new RemoteHomeServer(userId.Split(':')[1]); if (!servers.ContainsKey(hs)) servers.Add(hs, server); var profile = await server.GetProfileAsync(userId); - avatars.Add(userId, await hsResolver.ResolveMediaUri(server.FullHomeServerDomain, profile.AvatarUrl)); + avatars.Add(userId, await hsResolver.ResolveMediaUri(server.BaseUrl, profile.AvatarUrl)); servers.Add(userId, server); StateHasChanged(); } diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor index 9474b21..d0236e2 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/Space.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/Space.razor @@ -3,6 +3,7 @@ @using LibMatrix.Responses @using LibMatrix.RoomTypes @using ArcaneLibs.Extensions +@using LibMatrix <h3>Room manager - Viewing Space</h3> <button onclick="@JoinAllRooms">Join all rooms</button> @@ -93,10 +94,9 @@ // await base.OnInitializedAsync(); } - private Task JoinAllRooms() { - List<Task> tasks = Rooms.Select(room => room.JoinAsync(ServersInSpace.ToArray())).ToList(); - Task.WaitAll(tasks.ToArray()); - return Task.CompletedTask; + private async Task JoinAllRooms() { + List<Task<RoomIdResponse>> tasks = Rooms.Select(room => room.JoinAsync(ServersInSpace.ToArray())).ToList(); + await Task.WhenAll(tasks); } } diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor index f7a6106..e47ba11 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/StateEditor.razor @@ -2,6 +2,7 @@ @using LibMatrix.Extensions @using LibMatrix.Responses @using ArcaneLibs.Extensions +@using LibMatrix @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Room state editor - Editing @RoomId</h3> diff --git a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor index 6e8fe2f..e9c5da1 100644 --- a/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor +++ b/MatrixRoomUtils.Web/Pages/Rooms/StateViewer.razor @@ -2,6 +2,7 @@ @using LibMatrix.Extensions @using LibMatrix.Responses @using ArcaneLibs.Extensions +@using LibMatrix @inject ILocalStorageService LocalStorage @inject NavigationManager NavigationManager <h3>Room state viewer - Viewing @RoomId</h3> diff --git a/MatrixRoomUtils.Web/Pages/SpaceDebug.razor b/MatrixRoomUtils.Web/Pages/SpaceDebug.razor index 1ad6276..b07ba84 100644 --- a/MatrixRoomUtils.Web/Pages/SpaceDebug.razor +++ b/MatrixRoomUtils.Web/Pages/SpaceDebug.razor @@ -1,6 +1,7 @@ @page "/SpaceDebug" @using LibMatrix.RoomTypes @using LibMatrix.Filters +@using LibMatrix.Helpers <h3>SpaceDebug</h3> <hr/> @@ -48,10 +49,8 @@ var hs = await MRUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; - Status = "Syncing..."; - string nextBatch = null; - while (nextBatch != "end") { - var sync = await hs.SyncHelper.Sync(since: nextBatch, filter: new SyncFilter() { + var syncHelper = new SyncHelper(hs) { + Filter = new SyncFilter() { Presence = new(0), Room = new() { AccountData = new(limit: 0), @@ -60,8 +59,13 @@ Timeline = new(limit: 0) }, AccountData = new(limit: 0) - }); + } + }; + + Status = "Syncing..."; + var syncs = syncHelper.EnumerateSyncAsync(); + await foreach (var sync in syncs) { if (sync is null) { Status = "Sync failed"; continue; @@ -69,23 +73,20 @@ if (sync.Rooms is null) { Status = "No rooms in sync..."; - nextBatch = "end"; - continue; + break; } if (sync.Rooms.Join is null) { Status = "No joined rooms in sync..."; - nextBatch = "end"; - continue; + break; } if (sync.Rooms.Join.Count == 0) { Status = "Joined rooms list was empty..."; - nextBatch = "end"; - continue; + break; } - nextBatch = sync.NextBatch; + // nextBatch = sync.NextBatch; foreach (var (roomId, data) in sync.Rooms!.Join!) { data.State?.Events?.ForEach(e => { if (e.Type == "m.space.child") { diff --git a/MatrixRoomUtils.Web/Pages/User/Manage.razor b/MatrixRoomUtils.Web/Pages/User/Manage.razor new file mode 100644 index 0000000..281cbfc --- /dev/null +++ b/MatrixRoomUtils.Web/Pages/User/Manage.razor @@ -0,0 +1,55 @@ +@page "/User/Manage" +@using LibMatrix.Homeservers +@using LibMatrix.EventTypes.Spec.State +@using ArcaneLibs.Extensions +<h3>Manage user - @HomeServer?.WhoAmI?.UserId</h3> +<hr/> + +@if (Profile is not null) { + <h4>Profile</h4> + <hr/> + + <img src="@HomeServer.ResolveMediaUri(Profile.AvatarUrl)" style="width: 128px; height: 128px; border-radius: 50%;"/> + <div style="display: inline-block; vertical-align: middle;"> + <span>Display name: </span><FancyTextBox @bind-Value="@Profile.DisplayName"></FancyTextBox><br/> + <span>Avatar URL: </span><FancyTextBox @bind-Value="@Profile.AvatarUrl"></FancyTextBox> + <InputFile OnChange="@AvatarChanged"></InputFile><br/> + <LinkButton OnClick="@(() => UpdateProfile())">Update profile</LinkButton> + <LinkButton OnClick="@(() => UpdateProfile(true))">Update profile (restore room overrides)</LinkButton> + </div> + @if (Busy) { + <div>Busy processing profile update, please do not leave this page...</div> + } +} + +@code { + + private AuthenticatedHomeserverGeneric? HomeServer { get; set; } + private ProfileResponseEventContent? Profile { get; set; } + private bool Busy { get; set; } = false; + + protected override async Task OnInitializedAsync() { + HomeServer = await MRUStorage.GetCurrentSessionOrNavigate(); + if (HomeServer is null) return; + if (HomeServer.WhoAmI?.UserId is not null) + Profile = (await HomeServer.GetProfileAsync(HomeServer.WhoAmI.UserId)).DeepClone(); + + await base.OnInitializedAsync(); + } + + private async Task AvatarChanged(InputFileChangeEventArgs arg) { + var res = await HomeServer.UploadFile(arg.File.Name, arg.File.OpenReadStream(), arg.File.ContentType); + Console.WriteLine(res); + Profile.AvatarUrl = res; + StateHasChanged(); + } + + private async Task UpdateProfile(bool restoreRoomProfiles = false) { + Busy = true; + StateHasChanged(); + await HomeServer.UpdateProfileAsync(Profile, restoreRoomProfiles); + Busy = false; + StateHasChanged(); + } + +} \ No newline at end of file diff --git a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor index e82b505..3aea0e0 100644 --- a/MatrixRoomUtils.Web/Shared/InlineUserItem.razor +++ b/MatrixRoomUtils.Web/Shared/InlineUserItem.razor @@ -61,7 +61,7 @@ } - ProfileAvatar ??= await hsResolver.ResolveMediaUri(HomeServer.FullHomeServerDomain, User.AvatarUrl); + ProfileAvatar ??= await hsResolver.ResolveMediaUri(HomeServer.ServerName, User.AvatarUrl); ProfileName ??= User.DisplayName; _semaphoreSlim.Release(); diff --git a/MatrixRoomUtils.Web/Shared/NavMenu.razor b/MatrixRoomUtils.Web/Shared/NavMenu.razor index 48d3196..ad671c5 100644 --- a/MatrixRoomUtils.Web/Shared/NavMenu.razor +++ b/MatrixRoomUtils.Web/Shared/NavMenu.razor @@ -53,6 +53,12 @@ <span class="oi oi-plus" aria-hidden="true"></span> HS Admin </NavLink> </div> + + <div class="nav-item px-3"> + <NavLink class="nav-link" href="SpaceDebug"> + <span class="oi oi-plus" aria-hidden="true"></span> Space relationships + </NavLink> + </div> <div class="nav-item px-3"> <h5 style="margin-left: 1em;">MRU</h5> diff --git a/MatrixRoomUtils.Web/Shared/RoomListItem.razor b/MatrixRoomUtils.Web/Shared/RoomListItem.razor index d83568e..0e1d70d 100644 --- a/MatrixRoomUtils.Web/Shared/RoomListItem.razor +++ b/MatrixRoomUtils.Web/Shared/RoomListItem.razor @@ -9,9 +9,9 @@ @if (OwnMemberState != null) { <img class="imageUnloaded @(string.IsNullOrWhiteSpace(OwnMemberState?.AvatarUrl ?? GlobalProfile?.AvatarUrl) ? "" : "imageLoaded")" style="@(ChildContent is not null ? "vertical-align: baseline;" : "") width: 32px; height: 32px; border-radius: 50%; @(OwnMemberState?.AvatarUrl != GlobalProfile?.AvatarUrl ? "border-color: red; border-width: 3px; border-style: dashed;" : "")" - src="@hsResolver.ResolveMediaUri(hs.FullHomeServerDomain, OwnMemberState.AvatarUrl ?? GlobalProfile.AvatarUrl ?? "/icon-192.png").Result"/> + src="@hsResolver.ResolveMediaUri(hs.ServerName, OwnMemberState.AvatarUrl ?? GlobalProfile.AvatarUrl ?? "/icon-192.png").Result"/> <span style="vertical-align: middle; margin-right: 8px; border-radius: 75px; @(OwnMemberState?.AvatarUrl != GlobalProfile?.AvatarUrl ? "background-color: red;" : "")"> - @(OwnMemberState?.Displayname ?? GlobalProfile?.DisplayName ?? "Loading...") + @(OwnMemberState?.DisplayName ?? GlobalProfile?.DisplayName ?? "Loading...") </span> <span style="vertical-align: middle; padding-right: 8px; padding-left: 0px;">-></span> } @@ -137,7 +137,7 @@ var state = (await RoomInfo.GetStateEvent("m.room.avatar")).TypedContent as RoomAvatarEventContent; if (state?.Url is { } url) { - roomIcon = await hsResolver.ResolveMediaUri(hs.FullHomeServerDomain, url); + roomIcon = await hsResolver.ResolveMediaUri(hs.ServerName, url); // Console.WriteLine($"Got avatar for room {RoomId}: {roomIcon} ({url})"); } } diff --git a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor index 27c636f..b58afba 100644 --- a/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor +++ b/MatrixRoomUtils.Web/Shared/TimelineComponents/TimelineMemberItem.razor @@ -12,7 +12,7 @@ <i>@Event.StateKey was invited</i> break; case "join" when Event.ReplacesState is not null: - <i>@Event.StateKey changed their display name to @(roomMemberData.Displayname ?? Event.Sender)</i> + <i>@Event.StateKey changed their display name to @(roomMemberData.DisplayName ?? Event.Sender)</i> break; case "join": <i><InlineUserItem User="@(new ProfileResponseEventContent())" HomeServer="@Homeserver" UserId="@Event.StateKey"></InlineUserItem> joined</i> diff --git a/MatrixRoomUtils.Web/Shared/UserListItem.razor b/MatrixRoomUtils.Web/Shared/UserListItem.razor index 7c439cd..9010820 100644 --- a/MatrixRoomUtils.Web/Shared/UserListItem.razor +++ b/MatrixRoomUtils.Web/Shared/UserListItem.razor @@ -44,7 +44,7 @@ } // UserId = User.; - profileAvatar = await hsResolver.ResolveMediaUri(hs.FullHomeServerDomain, User.AvatarUrl); + profileAvatar = await hsResolver.ResolveMediaUri(hs.ServerName, User.AvatarUrl); profileName = User.DisplayName; _semaphoreSlim.Release(); diff --git a/MatrixRoomUtils.sln.DotSettings.user b/MatrixRoomUtils.sln.DotSettings.user index f9024a8..b2b542c 100644 --- a/MatrixRoomUtils.sln.DotSettings.user +++ b/MatrixRoomUtils.sln.DotSettings.user @@ -15,8 +15,8 @@ <s:Int64 x:Key="/Default/Environment/Hierarchy/Build/SolutionBuilderNext/ParallelProcessesCount2/@EntryValue">12</s:Int64> <s:Boolean x:Key="/Default/Environment/Hierarchy/Build/SolutionBuilderNext/ShouldRestoreNugetPackages/@EntryValue">True</s:Boolean> - <s:String x:Key="/Default/Environment/Highlighting/HighlightingSourceSnapshotLocation/@EntryValue">/home/root@Rory/.cache/JetBrains/Rider2023.2/resharper-host/temp/Rider/vAny/CoverageData/_MatrixRoomUtils.2147452914/Snapshot/snapshot.utdcvr</s:String> - <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=10c2dea2_002D6490_002D4ee9_002D8f89_002D2bf8c99bcf8e/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &lt;LibMatrix&gt; #5" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + + <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=10c2dea2_002D6490_002D4ee9_002D8f89_002D2bf8c99bcf8e/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="All tests from &lt;LibMatrix&gt; #5" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Project Location="/home/root@Rory/git/Matrix/MatrixRoomUtils" Presentation="&lt;LibMatrix&gt;" /> </SessionState></s:String> <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=24cf7b5e_002D6eb8_002D4f8e_002D80e5_002Dba9e1170805a/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="All tests from &lt;LibMatrix&gt; #4" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> @@ -41,7 +41,7 @@ <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=b41031ac_002Dfe6a_002D4ad7_002Db7d5_002D46c2a6404301/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="All tests from &lt;LibMatrix&gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Project Location="/home/root@Rory/git/Matrix/MatrixRoomUtils" Presentation="&lt;LibMatrix&gt;" /> </SessionState></s:String> - <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=c33adfe1_002D4af3_002D4c1e_002D9689_002De5e34a9f9113/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" Name="All tests from &lt;LibMatrix&gt; #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=c33adfe1_002D4af3_002D4c1e_002D9689_002De5e34a9f9113/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &lt;LibMatrix&gt; #2" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> <Project Location="/home/root@Rory/git/Matrix/MatrixRoomUtils" Presentation="&lt;LibMatrix&gt;" /> </SessionState></s:String> diff --git a/MxApiExtensions b/MxApiExtensions -Subproject 143b7fb859d97e815ed5340a1889db93e17a762 +Subproject 72b8f014866be5d0631a5b432b9d55569554e52 |