about summary refs log tree commit diff
path: root/MatrixUtils.Web/Shared/PolicyEditorComponents/PolicyEditorModal.razor
blob: 1bd00d1d3e5f2c8729a02a993587aef14447c5f2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
@using LibMatrix.EventTypes.Spec.State.Policy
@using System.Reflection
@using ArcaneLibs.Attributes
@using ArcaneLibs.Extensions
@using LibMatrix
@using System.Collections.Frozen
@using LibMatrix.EventTypes
<ModalWindow Title="@((string.IsNullOrWhiteSpace(PolicyEvent.EventId) ? "Creating new " : "Editing ") + (PolicyEvent.MappedType.GetFriendlyNameOrNull()?.ToLower() ?? "event"))"
             OnCloseClicked="@OnClose" X="60" Y="60" MinWidth="300">
    @if (string.IsNullOrWhiteSpace(PolicyEvent.EventId)) {
        <span>Policy type:</span>
        <select @bind="@MappedType">
            <option>Select a value</option>
            @foreach (var (type, mappedType) in PolicyTypes) {
                <option value="@type">@mappedType.GetFriendlyName().ToLower()</option>
            }
        </select>
    }

    @{
        // enumerate all properties with friendly name
        var props = PolicyEvent.MappedType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(x => (x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyNameOrNull()) is not null)
            .Where(x => x.GetCustomAttribute<TableHideAttribute>() is null)
            .ToFrozenSet();
        var propNames = props.Select(x => x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyName()!).ToFrozenSet();
    }
    @if (PolicyData is not null) {
        <table>
            <thead style="border-bottom: solid #ffffff44 1px;">
                <tr>
                    <th>Property</th>
                    <th>Value</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var prop in props) {
                    <tr>
                        <td style="padding-right: 8px;">
                            <span>@prop.GetFriendlyName()</span>
                            @if (Nullable.GetUnderlyingType(prop.PropertyType) is not null) {
                                <span style="color: red;">*</span>
                            }
                        </td>
                        @{
                            var getter = prop.GetGetMethod();
                            var setter = prop.GetSetMethod();
                        }
                        @switch (Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType) {
                            case Type t when t == typeof(string):
                                <FancyTextBox Value="@(getter?.Invoke(PolicyData, null) as string)" ValueChanged="@(e => { Console.WriteLine($"{prop.Name} ({setter is not null}) -> {e}"); setter?.Invoke(PolicyData, [e]); PolicyEvent.TypedContent = PolicyData; StateHasChanged(); })"></FancyTextBox>
                                break;
                            default:
                                <p style="color: red;">Unsupported type: @prop.PropertyType</p>
                                break;
                        }
                    </tr>
                }
            </tbody>
        </table>
        <br/>
        <pre>
            @PolicyEvent.ToJson(true, false)
        </pre>
        <LinkButton OnClick="@(() => { OnClose.Invoke(); return Task.CompletedTask; })"> Cancel </LinkButton>
        <LinkButton OnClick="@(() => { OnSave.Invoke(PolicyEvent); return Task.CompletedTask; })"> Save </LinkButton>
        @* <span>Target entity: </span> *@
        @* <FancyTextBox @bind-Value="@policyData.Entity"></FancyTextBox><br/> *@
        @* <span>Reason: </span> *@
        @* <FancyTextBox @bind-Value="@policyData.Reason"></FancyTextBox> *@
    }
    else {
        <p>Policy data is null</p>
    }
</ModalWindow>

@code {

    [Parameter]
    public StateEventResponse? PolicyEvent {
        get => _policyEvent;
        set {
            if (value is not null && value != _policyEvent)
                PolicyData = (value.TypedContent as PolicyRuleEventContent)!;
            _policyEvent = value;
            if (string.IsNullOrWhiteSpace(value.StateKey))
                value.StateKey = Guid.NewGuid().ToString();
        }
    }

    [Parameter]
    public required Action OnClose { get; set; }

    [Parameter]
    public required Action<StateEventResponse> OnSave { get; set; }

    public PolicyRuleEventContent? PolicyData { get; set; }

    private static FrozenSet<Type> KnownPolicyTypes = StateEvent.KnownStateEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))).ToFrozenSet();

    private static Dictionary<string, Type> PolicyTypes = KnownPolicyTypes
        .ToDictionary(x => x.GetCustomAttributes<MatrixEventAttribute>().First(y => !string.IsNullOrWhiteSpace(y.EventName)).EventName, x => x);

    private StateEventResponse? _policyEvent;
    
    private string? MappedType {
        get => _policyEvent?.Type;
        set {
            if (value is not null && PolicyTypes.ContainsKey(value)) {
                PolicyEvent.Type = value;
                PolicyEvent.TypedContent ??= Activator.CreateInstance(PolicyTypes[value]) as PolicyRuleEventContent;
                PolicyData = PolicyEvent.TypedContent as PolicyRuleEventContent;
            }
        }
    }
    

}