diff --git a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
index 334c05c..be78a97 100644
--- a/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
+++ b/MatrixRoomUtils.Core/Responses/CreateRoomRequest.cs
@@ -1,6 +1,8 @@
+using System.Reflection;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
+using MatrixRoomUtils.Core.Extensions;
using MatrixRoomUtils.Core.Interfaces;
using MatrixRoomUtils.Core.StateEventTypes;
using MatrixRoomUtils.Core.StateEventTypes.Spec;
@@ -21,7 +23,7 @@ public class CreateRoomRequest {
//we dont want to use this, we want more control
// [JsonPropertyName("preset")]
// public string Preset { get; set; } = null!;
-
+
[JsonPropertyName("initial_state")]
public List<StateEvent> InitialState { get; set; } = null!;
@@ -39,7 +41,21 @@ public class CreateRoomRequest {
/// </summary>
public StateEvent this[string event_type, string event_key = ""] {
- get => InitialState.First(x => x.Type == event_type && x.StateKey == event_key);
+ get {
+ var stateEvent = InitialState.FirstOrDefault(x => x.Type == event_type && x.StateKey == event_key);
+ if (stateEvent == null) {
+ InitialState.Add(stateEvent = new StateEvent {
+ Type = event_type,
+ StateKey = event_key,
+ TypedContent = Activator.CreateInstance(
+ StateEvent.KnownStateEventTypes.FirstOrDefault(x =>
+ x.GetCustomAttributes<MatrixEventAttribute>()?
+ .Any(y => y.EventName == event_type) ?? false) ?? typeof(object)
+ )
+ });
+ }
+ return stateEvent;
+ }
set {
var stateEvent = InitialState.FirstOrDefault(x => x.Type == event_type && x.StateKey == event_key);
if (stateEvent == null)
@@ -57,4 +73,4 @@ public class CreateRoomRequest {
return errors;
}
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
index 4bb7aeb..5e72471 100644
--- a/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
+++ b/MatrixRoomUtils.Web/MatrixRoomUtils.Web.csproj
@@ -11,6 +11,7 @@
<PackageReference Include="Blazored.SessionStorage" Version="2.3.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.7" PrivateAssets="all" />
+ <PackageReference Include="XtermBlazor" Version="1.9.0" />
</ItemGroup>
<ItemGroup>
diff --git a/MatrixRoomUtils.Web/Pages/About.razor b/MatrixRoomUtils.Web/Pages/About.razor
index cf43c4f..b8d9c4a 100644
--- a/MatrixRoomUtils.Web/Pages/About.razor
+++ b/MatrixRoomUtils.Web/Pages/About.razor
@@ -1,7 +1,9 @@
@page "/About"
@using System.Net
+@using System.Net.Sockets
@inject NavigationManager NavigationManager
@inject ILocalStorageService LocalStorage
+@using XtermBlazor
<PageTitle>About</PageTitle>
@@ -20,6 +22,9 @@
<p>This deployment also serves a copy of the compiled, hosting-ready binaries at <a href="MRU-SRC.tar.xz">/MRU-SRC.tar.xz</a>!</p>
}
+<Xterm @ref="_terminal" Options="_options" OnFirstRender="@OnFirstRender" style="max-width: fit-content; overflow-x: hidden;"/>
+
+
@code {
private bool showBinDownload { get; set; }
@@ -34,4 +39,29 @@
await base.OnInitializedAsync();
}
-}
\ No newline at end of file
+
+ private Xterm _terminal;
+
+ private TerminalOptions _options = new TerminalOptions
+ {
+ CursorBlink = true,
+ CursorStyle = CursorStyle.Block,
+ Theme =
+ {
+ Background = "#17615e",
+ },
+ };
+
+ private async Task OnFirstRender() {
+ var message = "Hello, World!\nThis is a terminal emulator!\n\nYou can type stuff here, and it will be sent to the server!\n\nThis is a test of the emergency broadcast system.\n\nThis is only a t";
+ _terminal.Options.RendererType = RendererType.Dom;
+ _terminal.Options.ScreenReaderMode = true;
+ TcpClient.
+ for (var i = 0; i < message.Length; i++) {
+ await _terminal.Write(message[i].ToString());
+
+ await Task.Delay(50);
+ _terminal.Options.Theme.Background = $"#{(i * 2):X6}";
+ }
+ }
+}
diff --git a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
index 4255424..3a98801 100644
--- a/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
+++ b/MatrixRoomUtils.Web/Pages/Rooms/Create.razor
@@ -12,213 +12,228 @@
<h3>Room Manager - Create Room</h3>
@* <pre Contenteditable="true" @onkeypress="@JsonChanged" content="JsonString">@JsonString</pre> *@
-<style>
- table.table-top-first-tr tr td:first-child {
- vertical-align: top;
- }
+<style>
+ table.table-top-first-tr tr td:first-child {
+ vertical-align: top;
+ }
</style>
<table class="table-top-first-tr">
- <tr>
- <td style="padding-bottom: 16px;">Preset:</td>
- <td style="padding-bottom: 16px;">
- <InputSelect @bind-Value="@RoomPreset">
- @foreach (var createRoomRequest in Presets) {
- <option value="@createRoomRequest.Key">@createRoomRequest.Key</option>
- }
- </InputSelect>
- </td>
- </tr>
- <tr>
- <td>Room name:</td>
- <td>
- <FancyTextBox @bind-Value="@creationEvent.Name"></FancyTextBox>
- </td>
- </tr>
- <tr>
- <td>Room alias (localpart):</td>
- <td>
- <FancyTextBox @bind-Value="@creationEvent.RoomAliasName"></FancyTextBox>
- </td>
- </tr>
- <tr>
- <td>Room type:</td>
- <td>
- <InputSelect @bind-Value="@creationEvent._creationContentBaseType.Type">
- <option value="">Room</option>
- <option value="m.space">Space</option>
- </InputSelect>
- <FancyTextBox @bind-Value="@creationEvent._creationContentBaseType.Type"></FancyTextBox>
- </td>
- </tr>
- <tr>
- <td style="padding-top: 16px;">History visibility:</td>
- <td style="padding-top: 16px;">
- @{
- var historyVisibility = creationEvent["m.room.history_visibility"].TypedContent as HistoryVisibilityEventData;
- }
- <InputSelect @bind-Value="@historyVisibility.HistoryVisibility">
- <option value="invited">Invited</option>
- <option value="joined">Joined</option>
- <option value="shared">Shared</option>
- <option value="world_readable">World readable</option>
- </InputSelect>
- </td>
- </tr>
- <tr>
- <td>Guest access:</td>
+ <tr style="padding-bottom: 16px;">
+ <td>Preset:</td>
<td>
- @{
- var guestAccessEvent = creationEvent["m.room.guest_access"].TypedContent as GuestAccessEventData;
+ @if (Presets is null) {
+ <p style="color: red;">Presets is null!</p>
}
- <ToggleSlider @bind-Value="guestAccessEvent.IsGuestAccessEnabled">
- @(guestAccessEvent.IsGuestAccessEnabled ? "Guests can join" : "Guests cannot join") (@guestAccessEvent.GuestAccess)
- </ToggleSlider>
- <InputSelect @bind-Value="@guestAccessEvent.GuestAccess">
- <option value="can_join">Can join</option>
- <option value="forbidden">Forbidden</option>
- </InputSelect>
- </td>
- </tr>
-
- <tr>
- <td>Room icon:</td>
- <td>
- @{
- var roomAvatarEvent = creationEvent["m.room.avatar"].TypedContent as RoomAvatarEventData;
+ else {
+ <InputSelect @bind-Value="@RoomPreset">
+ @foreach (var createRoomRequest in Presets) {
+ <option value="@createRoomRequest.Key">@createRoomRequest.Key</option>
+ }
+ </InputSelect>
}
- <img src="@MediaResolver.ResolveMediaUri(HomeServer.HomeServerDomain, 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>
- </div>
-
- </td>
- </tr>
- <tr>
- <td>Permissions:</td>
- <details>
- <summary>@creationEvent.PowerLevelContentOverride.Users.Count members</summary>
- @foreach (var user in creationEvent.PowerLevelContentOverride.Events.Keys) {
- var _event = user;
- <tr>
- <td>
- <FancyTextBox Formatter="@GetPermissionFriendlyName"
- Value="@_event"
- ValueChanged="val => { creationEvent.PowerLevelContentOverride.Events.ChangeKey(_event, val); }">
- </FancyTextBox>:
- </td>
- <td>
- <input type="number" value="@creationEvent.PowerLevelContentOverride.Events[_event]" @oninput="val => { creationEvent.PowerLevelContentOverride.Events[_event] = int.Parse(val.Value.ToString()); }" @onfocusout="() => { creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"/>
- </td>
- </tr>
- }
- @foreach (var user in creationEvent.PowerLevelContentOverride.Users.Keys) {
- var _user = user;
- <tr>
- <td><FancyTextBox Value="@_user" ValueChanged="val => { creationEvent.PowerLevelContentOverride.Users.ChangeKey(_user, val); creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"></FancyTextBox>:</td>
- <td>
- <input type="number" value="@creationEvent.PowerLevelContentOverride.Users[_user]" @oninput="val => { creationEvent.PowerLevelContentOverride.Users[_user] = int.Parse(val.Value.ToString()); }"/>
- </td>
- </tr>
- }
- </details>
- </tr>
- <tr>
- <td>Server ACLs:</td>
- <td>
- @{
- var serverAcl = creationEvent["m.room.server_acls"].TypedContent as ServerACLEventData;
- }
- <details>
- <summary>@((creationEvent["m.room.server_acls"].TypedContent as ServerACLEventData).Allow.Count) allow rules</summary>
- <StringListEditor @bind-Items="@serverAcl.Allow"></StringListEditor>
- </details>
- <details>
- <summary>@(creationEvent["m.room.server_acls"].TypedContent as ServerACLEventData).Deny.Count deny rules</summary>
- <StringListEditor @bind-Items="@serverAcl.Deny"></StringListEditor>
- </details>
</td>
</tr>
+ @if (creationEvent is not null) {
+ <tr>
+ <td>Room name:</td>
+ <td>
+ @if (creationEvent.Name is null) {
+ <p style="color: red;">creationEvent.Name is null!</p>
+ }
+ else {
+ <FancyTextBox @bind-Value="@creationEvent.Name"></FancyTextBox>
+ <p>(#<FancyTextBox @bind-Value="@creationEvent.RoomAliasName"></FancyTextBox>:@HomeServer.WhoAmI.UserId.Split(':').Last())</p>
+ }
+ </td>
+ </tr>
+ <tr>
+ <td>Room type:</td>
+ <td>
+ @if (creationEvent._creationContentBaseType is null) {
+ <p style="color: red;">creationEvent._creationContentBaseType is null!</p>
+ }
+ else {
+ <InputSelect @bind-Value="@creationEvent._creationContentBaseType.Type">
+ <option value="">Room</option>
+ <option value="m.space">Space</option>
+ </InputSelect>
+ <FancyTextBox @bind-Value="@creationEvent._creationContentBaseType.Type"></FancyTextBox>
+ }
+ </td>
+ </tr>
+ <tr>
+ <td style="padding-top: 16px;">History visibility:</td>
+ <td style="padding-top: 16px;">
+ <InputSelect @bind-Value="@historyVisibility.HistoryVisibility">
+ <option value="invited">Invited</option>
+ <option value="joined">Joined</option>
+ <option value="shared">Shared</option>
+ <option value="world_readable">World readable</option>
+ </InputSelect>
+ </td>
+ </tr>
+ <tr>
+ <td>Guest access:</td>
+ <td>
+ <ToggleSlider @bind-Value="guestAccessEvent.IsGuestAccessEnabled">
+ @(guestAccessEvent.IsGuestAccessEnabled ? "Guests can join" : "Guests cannot join") (@guestAccessEvent.GuestAccess)
+ </ToggleSlider>
+ <InputSelect @bind-Value="@guestAccessEvent.GuestAccess">
+ <option value="can_join">Can join</option>
+ <option value="forbidden">Forbidden</option>
+ </InputSelect>
+ </td>
+ </tr>
- <tr>
- <td>Invited members:</td>
- <td>
+ <tr>
+ <td>Room icon:</td>
+ <td>
+ <img src="@MediaResolver.ResolveMediaUri(HomeServer.HomeServerDomain, 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>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Permissions:</td>
<details>
- <summary>@creationEvent.InitialState.Count(x => x.Type == "m.room.member") members</summary>
- @* <button @onclick="() => { RuntimeCache.LoginSessions.Select(x => x.Value.LoginResponse.UserId).ToList().ForEach(InviteMember); }">Invite all logged in accounts</button> *@
- @foreach (var member in creationEvent.InitialState.Where(x => x.Type == "m.room.member" && x.StateKey != HomeServer.UserId)) {
- <UserListItem UserId="@member.StateKey"></UserListItem>
+ <summary>@creationEvent.PowerLevelContentOverride.Users.Count members</summary>
+ @foreach (var user in creationEvent.PowerLevelContentOverride.Events.Keys) {
+ var _event = user;
+ <tr>
+ <td>
+ <FancyTextBox Formatter="@GetPermissionFriendlyName"
+ Value="@_event"
+ ValueChanged="val => { creationEvent.PowerLevelContentOverride.Events.ChangeKey(_event, val); }">
+ </FancyTextBox>:
+ </td>
+ <td>
+ <input type="number" value="@creationEvent.PowerLevelContentOverride.Events[_event]" @oninput="val => { creationEvent.PowerLevelContentOverride.Events[_event] = int.Parse(val.Value.ToString()); }" @onfocusout="() => { creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"/>
+ </td>
+ </tr>
+ }
+ @foreach (var user in creationEvent.PowerLevelContentOverride.Users.Keys) {
+ var _user = user;
+ <tr>
+ <td><FancyTextBox Value="@_user" ValueChanged="val => { creationEvent.PowerLevelContentOverride.Users.ChangeKey(_user, val); creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value); }"></FancyTextBox>:</td>
+ <td>
+ <input type="number" value="@creationEvent.PowerLevelContentOverride.Users[_user]" @oninput="val => { creationEvent.PowerLevelContentOverride.Users[_user] = int.Parse(val.Value.ToString()); }"/>
+ </td>
+ </tr>
}
</details>
- </td>
- </tr>
- @* Initial states, should remain at bottom *@
- <tr>
- <td style="vertical-align: top;">Initial states:</td>
- <td>
- <details>
-
- @code
- {
- private static readonly string[] ImplementedStates = { "m.room.avatar", "m.room.history_visibility", "m.room.guest_access", "m.room.server_acl" };
+ </tr>
+ <tr>
+ <td>Server ACLs:</td>
+ <td>
+ @if (serverAcl?.Allow is null) {
+ <p>No allow rules exist!</p>
+ <button @onclick="@(() => { serverAcl.Allow = new() { "*" }; })">Create sane defaults</button>
}
+ else {
+ <details>
+ <summary>@((creationEvent["m.room.server_acls"].TypedContent as ServerACLEventData).Allow.Count) allow rules</summary>
+ @* <StringListEditor @bind-Items="@serverAcl.Allow"></StringListEditor> *@
+ </details>
+ }
+ @if (serverAcl?.Deny is null) {
+ <p>No deny rules exist!</p>
+ <button @onclick="@(() => { serverAcl.Allow = new(); })">Create sane defaults</button>
+ }
+ else {
+ <details>
+ <summary>@((creationEvent["m.room.server_acls"].TypedContent as ServerACLEventData).Deny.Count) deny rules</summary>
+ @* <StringListEditor @bind-Items="@serverAcl.Allow"></StringListEditor> *@
+ </details>
+ }
+ </td>
+ </tr>
- <summary> @creationEvent.InitialState.Count(x => !ImplementedStates.Contains(x.Type)) custom states</summary>
- <table>
- @foreach (var initialState in creationEvent.InitialState.Where(x => !ImplementedStates.Contains(x.Type))) {
- <tr>
- <td style="vertical-align: top;">
- @(initialState.Type):
- @if (!string.IsNullOrEmpty(initialState.StateKey)) {
- <br/>
- <span>(@initialState.StateKey)</span>
- }
-
- </td>
- <td>
- <pre>@JsonSerializer.Serialize(initialState.RawContent, new JsonSerializerOptions { WriteIndented = true })</pre>
- </td>
- </tr>
+ <tr>
+ <td>Invited members:</td>
+ <td>
+ <details>
+ <summary>@creationEvent.InitialState.Count(x => x.Type == "m.room.member") members</summary>
+ @* <button @onclick="() => { RuntimeCache.LoginSessions.Select(x => x.Value.LoginResponse.UserId).ToList().ForEach(InviteMember); }">Invite all logged in accounts</button> *@
+ @foreach (var member in creationEvent.InitialState.Where(x => x.Type == "m.room.member" && x.StateKey != HomeServer.UserId)) {
+ <UserListItem UserId="@member.StateKey"></UserListItem>
}
- </table>
- </details>
- <details>
- <summary> @creationEvent.InitialState.Count initial states</summary>
- <table>
- @foreach (var initialState in creationEvent.InitialState) {
- var _state = initialState;
- <tr>
- <td style="vertical-align: top;">
- <span>@(_state.Type):</span><br/>
- <button @onclick="() => { creationEvent.InitialState.Remove(_state); StateHasChanged(); }">Remove</button>
- </td>
+ </details>
+ </td>
+ </tr>
+ @* Initial states, should remain at bottom *@
+ <tr>
+ <td style="vertical-align: top;">Initial states:</td>
+ <td>
+ <details>
- <td>
- <pre>@JsonSerializer.Serialize(_state.RawContent, new JsonSerializerOptions { WriteIndented = true })</pre>
- </td>
- </tr>
+ @code
+ {
+ private static readonly string[] ImplementedStates = { "m.room.avatar", "m.room.history_visibility", "m.room.guest_access", "m.room.server_acl" };
}
- </table>
- </details>
- </td>
- </tr>
+
+ <summary> @creationEvent.InitialState.Count(x => !ImplementedStates.Contains(x.Type)) custom states</summary>
+ <table>
+ @foreach (var initialState in creationEvent.InitialState.Where(x => !ImplementedStates.Contains(x.Type))) {
+ <tr>
+ <td style="vertical-align: top;">
+ @(initialState.Type):
+ @if (!string.IsNullOrEmpty(initialState.StateKey)) {
+ <br/>
+ <span>(@initialState.StateKey)</span>
+ }
+
+ </td>
+ <td>
+ <pre>@JsonSerializer.Serialize(initialState.RawContent, new JsonSerializerOptions { WriteIndented = true })</pre>
+ </td>
+ </tr>
+ }
+ </table>
+ </details>
+ <details>
+ <summary> @creationEvent.InitialState.Count initial states</summary>
+ <table>
+ @foreach (var initialState in creationEvent.InitialState) {
+ var _state = initialState;
+ <tr>
+ <td style="vertical-align: top;">
+ <span>@(_state.Type):</span><br/>
+ <button @onclick="() => { creationEvent.InitialState.Remove(_state); StateHasChanged(); }">Remove</button>
+ </td>
+
+ <td>
+ <pre>@JsonSerializer.Serialize(_state.RawContent, new JsonSerializerOptions { WriteIndented = true })</pre>
+ </td>
+ </tr>
+ }
+ </table>
+ </details>
+ </td>
+ </tr>
}
</table>
<button @onclick="CreateRoom">Create room</button>
<br/>
-<details>
- <summary>Creation JSON</summary>
+<ModalWindow Title="Creation JSON">
<pre>
- @creationEvent.ToJson(ignoreNull: true)
- </pre>
-</details>
-<details open>
- <summary>Creation JSON (with null values)</summary>
+ @creationEvent.ToJson(ignoreNull: true)
+ </pre>
+</ModalWindow>
+<ModalWindow Title="Creation JSON (with null values)">
<pre>
- @creationEvent.ToJson()
- </pre>
-</details>
+ @creationEvent.ToJson()
+ </pre>
+</ModalWindow>
+@if (_matrixException is not null) {
+ <ModalWindow Title="@("Matrix exception: " + _matrixException.ErrorCode)">
+ <pre>
+ @_matrixException.Message
+ </pre>
+ </ModalWindow>
+}
@code {
@@ -232,22 +247,22 @@
set {
creationEvent = Presets[value];
JsonChanged();
-
- creationEvent.PowerLevelContentOverride.Events = creationEvent.PowerLevelContentOverride.Events.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
- creationEvent.PowerLevelContentOverride.Users = creationEvent.PowerLevelContentOverride.Users.OrderByDescending(x => x.Value).ThenBy(x => x.Key).ToDictionary(x => x.Key, x => x.Value);
- guestAccessEvent = creationEvent["m.room.guest_access"].TypedContent as GuestAccessEventData;
StateHasChanged();
}
}
- private Dictionary<string, string> creationEventValidationErrors { get; set; } = new();
+ private CreateRoomRequest? creationEvent { get; set; }
- private CreateRoomRequest creationEvent { get; set; }
- GuestAccessEventData guestAccessEvent { get; set; }
-
- private Dictionary<string, CreateRoomRequest> Presets { get; set; } = new();
+ private Dictionary<string, CreateRoomRequest>? Presets { get; set; } = new();
private AuthenticatedHomeServer? HomeServer { get; set; }
+ private MatrixException? _matrixException { get; set; }
+
+ private HistoryVisibilityEventData? historyVisibility => creationEvent?["m.room.history_visibility"].TypedContent as HistoryVisibilityEventData;
+ private GuestAccessEventData? guestAccessEvent => creationEvent?["m.room.guest_access"].TypedContent as GuestAccessEventData;
+ private ServerACLEventData? serverAcl => creationEvent?["m.room.server_acls"].TypedContent as ServerACLEventData;
+ private RoomAvatarEventData? roomAvatarEvent => creationEvent?["m.room.avatar"].TypedContent as RoomAvatarEventData;
+
protected override async Task OnInitializedAsync() {
HomeServer = await MRUStorage.GetCurrentSessionOrNavigate();
if (HomeServer is null) return;
@@ -280,7 +295,12 @@
Console.WriteLine("Create room");
Console.WriteLine(creationEvent.ToJson());
creationEvent.CreationContent.Add("rory.gay.created_using", "Rory&::MatrixRoomUtils (https://mru.rory.gay)");
- var id = await HomeServer.CreateRoom(creationEvent);
+ try {
+ var id = await HomeServer.CreateRoom(creationEvent);
+ }
+ catch (MatrixException e) {
+ _matrixException = e;
+ }
}
private void InviteMember(string mxid) {
@@ -295,28 +315,28 @@
});
}
- private string GetStateFriendlyName(string key) => key switch {
- "m.room.history_visibility" => "History visibility",
- "m.room.guest_access" => "Guest access",
- "m.room.join_rules" => "Join rules",
- "m.room.server_acl" => "Server ACL",
- "m.room.avatar" => "Avatar",
- _ => key
+ private string GetStateFriendlyName(string key) => key switch {
+ "m.room.history_visibility" => "History visibility",
+ "m.room.guest_access" => "Guest access",
+ "m.room.join_rules" => "Join rules",
+ "m.room.server_acl" => "Server ACL",
+ "m.room.avatar" => "Avatar",
+ _ => key
};
- private string GetPermissionFriendlyName(string key) => key switch {
- "m.reaction" => "Send reaction",
- "m.room.avatar" => "Change room icon",
- "m.room.canonical_alias" => "Change room alias",
- "m.room.encryption" => "Enable encryption",
- "m.room.history_visibility" => "Change history visibility",
- "m.room.name" => "Change room name",
- "m.room.power_levels" => "Change power levels",
- "m.room.tombstone" => "Upgrade room",
- "m.room.topic" => "Change room topic",
- "m.room.pinned_events" => "Pin events",
- "m.room.server_acl" => "Change server ACLs",
- _ => key
+ private string GetPermissionFriendlyName(string key) => key switch {
+ "m.reaction" => "Send reaction",
+ "m.room.avatar" => "Change room icon",
+ "m.room.canonical_alias" => "Change room alias",
+ "m.room.encryption" => "Enable encryption",
+ "m.room.history_visibility" => "Change history visibility",
+ "m.room.name" => "Change room name",
+ "m.room.power_levels" => "Change power levels",
+ "m.room.tombstone" => "Upgrade room",
+ "m.room.topic" => "Change room topic",
+ "m.room.pinned_events" => "Pin events",
+ "m.room.server_acl" => "Change server ACLs",
+ _ => key
};
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Shared/ModalWindow.razor b/MatrixRoomUtils.Web/Shared/ModalWindow.razor
index 75c2933..216f1f3 100644
--- a/MatrixRoomUtils.Web/Shared/ModalWindow.razor
+++ b/MatrixRoomUtils.Web/Shared/ModalWindow.razor
@@ -1,95 +1,37 @@
<div class="r-modal" style="top: @(_y)px; left: @(_x)px;">
<div class="titlebar" @onmousedown="MouseDown" @onmouseup="MouseUp" @onmousemove="MouseMove" @onmouseleave="MouseMove">
<b class="title">@Title</b>
- <button class="close" @onclick="OnCloseClicked">X</button>
- </div>
- <div class="content">
- @ChildContent
+ <button class="btnclose" @onclick="OnCloseClicked">X</button>
+ <button class="btncollapse" @onclick="@(() => Collapsed = !Collapsed)">_</button>
</div>
+ <div class="content" style="@(Collapsed ? "height: 0px;" : "")">
+ @ChildContent
+ </div>
</div>
-<style>
- .r-modal {
- position: absolute;
- width: fit-content;
- height: fit-content;
- z-index: 1000;
- }
- .r-modal:hover {
- z-index: 1001;
- }
-
- .r-modal > .titlebar {
- position: absolute;
- display: block;
- top: 0;
- left: 0;
- width: 100%;
- height: 25px;
- background-color: #000;
- user-select: none;
- }
-
- .r-modal > .titlebar > .title {
- position: relative;
- top: 0;
- left: 0;
- width: fit-content;
- height: 100%;
- line-height: 25px;
- padding-left: 10px;
- color: #fff;
- }
-
- .r-modal > .titlebar > .close {
- position: absolute;
- top: 0;
- right: 0;
- width: 25px;
- height: 100%;
- line-height: 25px;
- text-align: center;
- color: #fff;
- background-color: #111;
- cursor: pointer;
- }
-
- .r-modal > .content {
- position: relative;
- top: 25px;
- left: 0;
- width: fit-content;
- height: fit-content;
- min-width: 150px;
- min-height: 5px;
- max-width: 75vw;
- max-height: 75vh;
- overflow: auto;
- background-color: #fff;
- }
-</style>
-
@code {
-
+
[Parameter]
public RenderFragment? ChildContent { get; set; }
-
+
[Parameter]
public string Title { get; set; } = "Untitled window";
-
+
[Parameter]
public double X { get; set; } = 60;
-
+
[Parameter]
public double Y { get; set; } = 60;
-
+
[Parameter]
public Action OnCloseClicked { get; set; }
-
+
+ [Parameter]
+ public bool Collapsed { get; set; } = false;
private double _x = 60;
private double _y = 60;
-
+
protected override void OnInitialized() {
_x = X;
_y = Y;
@@ -97,16 +39,17 @@
private void WindowDrag(DragEventArgs obj) {
Console.WriteLine("Drag: " + obj.ToJson());
-
+
_x += obj.MovementX;
_y += obj.MovementY;
-
+
StateHasChanged();
}
private bool isDragging = false;
private double dragX = 0;
private double dragY = 0;
+
private void MouseDown(MouseEventArgs obj) {
isDragging = true;
dragX = obj.ClientX;
@@ -127,4 +70,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/MatrixRoomUtils.Web/Shared/ModalWindow.razor.css b/MatrixRoomUtils.Web/Shared/ModalWindow.razor.css
new file mode 100644
index 0000000..b25ab0e
--- /dev/null
+++ b/MatrixRoomUtils.Web/Shared/ModalWindow.razor.css
@@ -0,0 +1,70 @@
+.r-modal {
+ position: absolute;
+ width: fit-content;
+ height: fit-content;
+ z-index: 1000;
+}
+.r-modal:hover {
+ z-index: 1001;
+}
+
+.r-modal > .titlebar {
+ position: absolute;
+ display: block;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 25px;
+ background-color: #000;
+ user-select: none;
+}
+
+.r-modal > .titlebar > .title {
+ position: relative;
+ top: 0;
+ left: 0;
+ width: fit-content;
+ height: 100%;
+ line-height: 25px;
+ padding-left: 10px;
+ color: #fff;
+}
+
+.r-modal > .titlebar > .btnclose {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 25px;
+ height: 100%;
+ line-height: 25px;
+ text-align: center;
+ color: #fff;
+ background-color: #111;
+ cursor: pointer;
+}
+.r-modal > .titlebar > .btncollapse {
+ position: absolute;
+ top: 0;
+ right: 25px;
+ width: 25px;
+ height: 100%;
+ line-height: 25px;
+ text-align: center;
+ color: #fff;
+ background-color: #111;
+ cursor: pointer;
+}
+
+.r-modal > .content {
+ position: relative;
+ top: 25px;
+ left: 0;
+ width: fit-content;
+ height: fit-content;
+ min-width: 150px;
+ min-height: 5px;
+ max-width: 75vw;
+ max-height: 75vh;
+ overflow: auto;
+ background-color: #111;
+}
diff --git a/MatrixRoomUtils.Web/wwwroot/index.html b/MatrixRoomUtils.Web/wwwroot/index.html
index 9c9e7d0..0598c4d 100644
--- a/MatrixRoomUtils.Web/wwwroot/index.html
+++ b/MatrixRoomUtils.Web/wwwroot/index.html
@@ -10,6 +10,8 @@
<link href="css/app.css" rel="stylesheet"/>
<link href="favicon.png" rel="icon" type="image/png"/>
<link href="MatrixRoomUtils.Web.styles.css" rel="stylesheet"/>
+ <link href="_content/XtermBlazor/XtermBlazor.css" rel="stylesheet" />
+ <script src="_content/XtermBlazor/XtermBlazor.min.js"></script>
</head>
<body>
diff --git a/MatrixRoomUtils.sln.DotSettings.user b/MatrixRoomUtils.sln.DotSettings.user
index 33f4f70..785af7c 100644
--- a/MatrixRoomUtils.sln.DotSettings.user
+++ b/MatrixRoomUtils.sln.DotSettings.user
@@ -7,13 +7,14 @@
<s:Boolean x:Key="/Default/Environment/Hierarchy/Build/SolutionBuilderNext/ShouldRestoreNugetPackages/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=244e90fe_002Dee26_002D4f78_002D86eb_002D27529ae48905_0023MatrixRoomUtils/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=f997f26f_002D2ec1_002D4d18_002Db3dd_002Dc46fb2ad65c0_0023MatrixRoomUtils_002EWeb_002EServer/@EntryIndexedValue">True</s:Boolean>
+
- <s:Boolean x:Key="/Default/UnloadedProject/UnloadedProjects/=f997f26f_002D2ec1_002D4d18_002Db3dd_002Dc46fb2ad65c0_0023MatrixRoomUtils_002EWeb_002EServer/@EntryIndexedValue">True</s:Boolean>
|