From 89a14526658e5d061b1aef34ab569e979c9c0cf8 Mon Sep 17 00:00:00 2001 From: Rory& Date: Wed, 6 Aug 2025 03:15:16 +0200 Subject: Various changes, room create/upgrade work --- .../PolicyListCategoryComponent.razor | 66 ++++++++ .../PolicyListEditorHeader.razor | 65 ++++++++ .../PolicyListRowComponent.razor | 167 +++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListCategoryComponent.razor create mode 100644 MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListEditorHeader.razor create mode 100644 MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListRowComponent.razor (limited to 'MatrixUtils.Web/Pages/Rooms/PolicyListComponents') diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListCategoryComponent.razor b/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListCategoryComponent.razor new file mode 100644 index 0000000..f818b62 --- /dev/null +++ b/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListCategoryComponent.razor @@ -0,0 +1,66 @@ +@using ArcaneLibs.Extensions +@using LibMatrix.RoomTypes +
+ + + @($"{PolicyCollection.Name}: {PolicyCollection.TotalCount} policies") + +
+
+ + + + @foreach (var name in PolicyCollection.PropertiesToDisplay!.Keys) { + + } + + + + + @foreach (var policy in PolicyCollection.ActivePolicies.Values.OrderBy(x => x.Policy.RawContent?["entity"]?.GetValue())) { + + } + +
@nameActions
+
+ + + @("Invalid " + PolicyCollection.Name.ToLower()) + + + + + + + + + + + @foreach (var policy in PolicyCollection.RemovedPolicies.Values) { + + + + + } + +
State keyJson contents
@policy.Policy.StateKey +
@policy.Policy.RawContent.ToJson(true, false)
+
+
+
+ +@code { + + [Parameter] + public required PolicyList.PolicyCollection PolicyCollection { get; set; } + + [Parameter] + public required GenericRoom Room { get; set; } + + protected override bool ShouldRender() { + // if (PolicyCollection is null) return false; + + return true; + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListEditorHeader.razor b/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListEditorHeader.razor new file mode 100644 index 0000000..e82f17d --- /dev/null +++ b/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListEditorHeader.razor @@ -0,0 +1,65 @@ +@using LibMatrix +@using LibMatrix.EventTypes.Common +@using LibMatrix.RoomTypes +@using MatrixUtils.Web.Shared.PolicyEditorComponents +

Policy list editor - Editing @(RoomName ?? Room.RoomId)

+@if (!string.IsNullOrWhiteSpace(DraupnirShortcode)) { + Shortcode: @DraupnirShortcode +} +@if (!string.IsNullOrWhiteSpace(RoomAlias)) { + Alias: @RoomAlias +} +
+@* *@ +Create new policy + +Create many new policies + +Refresh + +@if (CurrentlyEditingEvent is not null) { + +} + +@if (MassCreatePolicies) { + +} + +@code { + [Parameter] + public required GenericRoom Room { get; set; } + + [Parameter] + public required Func ReloadStateAsync { get; set; } + + private string? RoomName { get; set; } + private string? RoomAlias { get; set; } + private string? DraupnirShortcode { get; set; } + + private StateEventResponse? CurrentlyEditingEvent { get; set { field = value; StateHasChanged(); } } + private bool MassCreatePolicies { get; set { field = value; StateHasChanged(); } } + + protected override async Task OnInitializedAsync() { + await Task.WhenAll( + Task.Run(async () => { DraupnirShortcode = (await Room.GetStateOrNullAsync(MjolnirShortcodeEventContent.EventId))?.Shortcode; }), + Task.Run(async () => { RoomAlias = (await Room.GetCanonicalAliasAsync())?.Alias; }), + Task.Run(async () => { RoomName = await Room.GetNameOrFallbackAsync(); }) + ); + + StateHasChanged(); + } + + private async Task UpdatePolicyAsync(StateEventResponse evt) { + Console.WriteLine("UpdatePolicyAsync in PolicyListEditorHeader not yet implementeD!"); + } + +} \ No newline at end of file diff --git a/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListRowComponent.razor b/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListRowComponent.razor new file mode 100644 index 0000000..11de82c --- /dev/null +++ b/MatrixUtils.Web/Pages/Rooms/PolicyListComponents/PolicyListRowComponent.razor @@ -0,0 +1,167 @@ +@using System.Reflection +@using LibMatrix +@using LibMatrix.EventTypes.Spec.State.Policy +@using LibMatrix.RoomTypes +@using MatrixUtils.Web.Shared.PolicyEditorComponents + +@if (_isInitialized && IsVisible) { + + @foreach (var prop in PolicyCollection.PropertiesToDisplay.Values) { + if (prop.Name == "Entity") { + + @TruncateMxid(TypedContent.Entity) + @foreach (var dup in PolicyInfo.MadeRedundantBy) { +
+ Also matched by @dup.FriendlyTypeName.ToLower() @TruncateMxid(dup.RawContent["entity"].GetValue()) + } + + } + else { + @prop.GetGetMethod()?.Invoke(TypedContent, null) + } + } + +
+ @* @if (PowerLevels.UserHasStatePermission(Homeserver.WhoAmI.UserId, Policy.Type)) { *@ + @if (true) { + Edit + + Remove + @if (Policy.IsLegacyType) { + Update policy type + } + + @if (TypedContent.Entity?.StartsWith("@*:", StringComparison.Ordinal) == true) { + Convert to ACL + } + + @* @if (PolicyTypeIds[typeof(ServerPolicyRuleEventContent)].Contains(Policy.Type)) { *@ + @* Make permanent *@ + @* *@ + @* @if (CurrentUserIsDraupnir) { *@ + @* Kick *@ + @* users @(ActiveKicks.TryGetValue(Policy, out var kick) ? $"({kick})" : null) *@ + @* *@ + @* } *@ + // } + } + else { +

No permission to modify

+ } +
+ + + + @if (IsEditing) { + + } + @* TODO: Implement ability to turn ACLs into wildcards *@ + @*@if (ServerPolicyToMakePermanent is not null) { + + + + }*@ +} + + + +@code { + + [Parameter] + public PolicyList.PolicyCollection.PolicyInfo PolicyInfo { get; set; } + + [Parameter] + public GenericRoom Room { get; set; } = null!; + + [Parameter] + public required PolicyList.PolicyCollection PolicyCollection { get; set; } + + private StateEventResponse Policy => PolicyInfo.Policy; + + private bool IsEditing { + get; + set { + field = value; + _isDirty = true; + StateHasChanged(); + } + } + + public bool IsVisible { + get; + set { + field = value; + _isDirty = true; + } + } = true; + + private PolicyRuleEventContent TypedContent { get; set; } + + private bool _isDirty = true; + private bool _isInitialized; + + protected override bool ShouldRender() => _isDirty; + + protected override void OnParametersSet() { + TypedContent = Policy.TypedContent as PolicyRuleEventContent ?? throw new InvalidOperationException("Policy must have a typed content of type PolicyRuleEventContent."); + _isDirty = true; + _isInitialized = true; + // Console.WriteLine($"ParametersSet {Policy.StateKey}"); + } + + private static string TruncateMxid(string? mxid) { + if (string.IsNullOrWhiteSpace(mxid)) return mxid; + var parts = mxid.Split(':', 2); + if (parts[0].Length > 50) + parts[0] = parts[0][..50] + "[...]"; + + if (parts is [_, { Length: > 50 }]) + parts[1] = parts[1][..50] + "[...]"; + + return parts.Length == 1 ? parts[0] : $"{parts[0]}:{parts[1]}"; + } + + private async Task RemovePolicyAsync() { + await Room.SendStateEventAsync(Policy.Type, Policy.StateKey, new { }); + IsVisible = false; + StateHasChanged(); + // PolicyEventsByType[policyEvent.MappedType].Remove(policyEvent); + // await LoadStatesAsync(); + } + + private async Task UpdatePolicyAsync(StateEventResponse evt) { + await Room.SendStateEventAsync(Policy.Type, Policy.StateKey, Policy.RawContent); + // CurrentlyEditingEvent = null; + // await LoadStatesAsync(); + } + + private async Task UpgradePolicyAsync() { + Policy.RawContent["gay.rory.matrixutils.upgraded_from_type"] = Policy.Type; + // await LoadStatesAsync(); + } + + private async Task ConvertToAclAsync() { + if (Policy.RawContent.ContainsKey("entity")) { + var newContent = Policy.ContentAs(); + newContent!.Entity = newContent.Entity!.Replace("@*:", ""); + await Room.SendStateEventAsync(ServerPolicyRuleEventContent.EventId, newContent.GetDraupnir2StateKey(), newContent); + await Room.SendStateEventAsync(Policy.Type, Policy.StateKey!, new { }); + IsVisible = false; + StateHasChanged(); + } + else { + throw new InvalidOperationException("Policy event must contain an 'entity' field to convert to ACL."); + } + } + + private string Anchor(string anchor) { + return $"{NavigationManager.Uri.Split('#')[0]}#{anchor}"; + } + +} \ No newline at end of file -- cgit 1.5.1