diff --git a/OryAdmin/Components/Pages/Identities/Users/Create.razor b/OryAdmin/Components/Pages/Identities/Users/Create.razor index 1e15c34..233e189 100644 --- a/OryAdmin/Components/Pages/Identities/Users/Create.razor +++ b/OryAdmin/Components/Pages/Identities/Users/Create.razor @@ -43,14 +43,14 @@ else
- @foreach (var schema in _traitsSchemas!) + @foreach (var (schemaPathSections, schema) in _traitsSchemas!) {
diff --git a/OryAdmin/Components/Pages/Identities/Users/Create.razor.cs b/OryAdmin/Components/Pages/Identities/Users/Create.razor.cs index 9a46dfa..0744aba 100644 --- a/OryAdmin/Components/Pages/Identities/Users/Create.razor.cs +++ b/OryAdmin/Components/Pages/Identities/Users/Create.razor.cs @@ -1,22 +1,21 @@ using Microsoft.AspNetCore.Components; using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; using Ory.Kratos.Client.Client; using Ory.Kratos.Client.Model; -using OryAdmin.Extensions; -using OryAdmin.Models; using OryAdmin.Services; namespace OryAdmin.Components.Pages.Identities.Users; public partial class Create { - private JObject _json = new(); private string? _errorMessage; private bool _isLoading = true; + private readonly JObject _json = new(); private bool _schemaDropdownActive; private List? _schemaIds; - private List? _traitsSchemas; + private Dictionary, JSchema>? _traitsSchemas; [SupplyParameterFromQuery(Name = "schema")] private string? SelectedSchemaId { get; set; } @@ -35,7 +34,7 @@ protected override async Task OnParametersSetAsync() { _schemaIds ??= await SchemaService.ListIds(); SelectedSchemaId ??= _schemaIds.First(); - _traitsSchemas = await SchemaService.GetTraitSchemas(SelectedSchemaId); + _traitsSchemas = await SchemaService.GetTraits(SelectedSchemaId); } private void OnSelectionChanged() @@ -58,9 +57,4 @@ private async Task SubmitForm() nav.NavigateTo("identities/users"); } - - private void UpdateValue(TraitsSchemaData schema, ChangeEventArgs args) - { - _json.UpdateValueWithSchema(schema, args.Value); - } } \ No newline at end of file diff --git a/OryAdmin/Components/Pages/Identities/Users/Edit.razor b/OryAdmin/Components/Pages/Identities/Users/Edit.razor index a2e9607..f510ad6 100644 --- a/OryAdmin/Components/Pages/Identities/Users/Edit.razor +++ b/OryAdmin/Components/Pages/Identities/Users/Edit.razor @@ -13,16 +13,16 @@ else { - @foreach (var schema in _traitSchemas!) + @foreach (var (schemaPathSections, schema) in _traitSchemas!) { - var value = _json!.GetTraitValueFromPath(schema.Path); + var value = _json!.GetTraitValueFromPath(schemaPathSections);
diff --git a/OryAdmin/Components/Pages/Identities/Users/Edit.razor.cs b/OryAdmin/Components/Pages/Identities/Users/Edit.razor.cs index 37a0da4..ef53bfa 100644 --- a/OryAdmin/Components/Pages/Identities/Users/Edit.razor.cs +++ b/OryAdmin/Components/Pages/Identities/Users/Edit.razor.cs @@ -1,9 +1,8 @@ using Microsoft.AspNetCore.Components; using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; using Ory.Kratos.Client.Client; using Ory.Kratos.Client.Model; -using OryAdmin.Extensions; -using OryAdmin.Models; using OryAdmin.Services; namespace OryAdmin.Components.Pages.Identities.Users; @@ -14,7 +13,7 @@ public partial class Edit private KratosIdentity? _identity; private bool _isLoading = true; private JObject? _json; - private List? _traitSchemas; + private Dictionary, JSchema>? _traitSchemas; [Parameter] public string? UserId { get; set; } [Inject] private ApiService ApiService { get; set; } = default!; [Inject] private IdentitySchemaService SchemaService { get; set; } = default!; @@ -23,7 +22,7 @@ protected override async Task OnInitializedAsync() { _identity = await ApiService.KratosIdentity.GetIdentityAsync(UserId); _json = (JObject?)_identity.Traits; - _traitSchemas = await SchemaService.GetTraitSchemas(_identity.SchemaId); + _traitSchemas = await SchemaService.GetTraits(_identity.SchemaId); _isLoading = false; } @@ -48,8 +47,7 @@ private async Task SubmitForm() nav.NavigateTo($"identities/users/{UserId}"); } - private void UpdateValue(TraitsSchemaData schema, ChangeEventArgs args) + private void UpdateValue(JSchema schema, ChangeEventArgs args) { - _json!.UpdateValueWithSchema(schema, args.Value); } } \ No newline at end of file diff --git a/OryAdmin/Components/Pages/Identities/Users/Sessions.razor b/OryAdmin/Components/Pages/Identities/Users/Sessions.razor index 83b4a37..e85c642 100644 --- a/OryAdmin/Components/Pages/Identities/Users/Sessions.razor +++ b/OryAdmin/Components/Pages/Identities/Users/Sessions.razor @@ -1,4 +1,5 @@ @page "/identities/users/{UserId}/sessions" +@using UAParser @rendermode InteractiveServer @inject NavigationManager nav @@ -11,6 +12,7 @@ } else { + var uaParser = Parser.GetDefault();

Active Sessions

@if (_activeSessions!.Count == 0) @@ -40,7 +42,12 @@ else @foreach (var device in session.Devices) { -

@device.Id (@device.IpAddress)

+ var info = uaParser.Parse(device.UserAgent); +

+ @info.Device.Family on @info.OS + @device.IpAddress + @(string.IsNullOrWhiteSpace(device.Location) ? "" : $"({device.Location})") +

} @@ -118,7 +125,12 @@ else @foreach (var device in session.Devices) { -

@device.Id (@device.IpAddress)

+ var info = uaParser.Parse(device.UserAgent); +

+ @info.Device.Family on @info.OS + @device.IpAddress + @(string.IsNullOrWhiteSpace(device.Location) ? "" : $"({device.Location})") +

} diff --git a/OryAdmin/Components/Pages/Identities/Users/View.razor b/OryAdmin/Components/Pages/Identities/Users/View.razor index a29328a..91bae4e 100644 --- a/OryAdmin/Components/Pages/Identities/Users/View.razor +++ b/OryAdmin/Components/Pages/Identities/Users/View.razor @@ -1,4 +1,5 @@ @page "/identities/users/{UserId}" +@using UAParser @rendermode InteractiveServer @inject NavigationManager nav @@ -116,6 +117,9 @@ else + @{ + var uaParser = Parser.GetDefault(); + } @foreach (var session in _activeSessions!) { @@ -125,7 +129,12 @@ else @foreach (var device in session.Devices) { -

@device.Id (@device.IpAddress)

+ var info = uaParser.Parse(device.UserAgent); +

+ @info.Device.Family on @info.OS + @device.IpAddress + @(string.IsNullOrWhiteSpace(device.Location) ? "" : $"({device.Location})") +

} diff --git a/OryAdmin/Components/_Imports.razor b/OryAdmin/Components/_Imports.razor index fc457af..5aa604e 100644 --- a/OryAdmin/Components/_Imports.razor +++ b/OryAdmin/Components/_Imports.razor @@ -10,5 +10,4 @@ @using OryAdmin.Components @using OryAdmin.Extensions @using OryAdmin.Components.Elements -@using OryAdmin.Models; @using OryAdmin.Services; \ No newline at end of file diff --git a/OryAdmin/Extensions/JObjectExt.cs b/OryAdmin/Extensions/JObjectExt.cs index df5ff2e..56e5ec8 100644 --- a/OryAdmin/Extensions/JObjectExt.cs +++ b/OryAdmin/Extensions/JObjectExt.cs @@ -1,15 +1,16 @@ using Newtonsoft.Json.Linq; -using OryAdmin.Models; +using Newtonsoft.Json.Schema; namespace OryAdmin.Extensions; public static class JObjectExt { - public static void UpdateValueWithSchema(this JObject json, TraitsSchemaData schema, object? value) + public static void UpdateValueWithSchema(this JObject json, JSchema schema, List schemaPathSections, + object? value) { JObject? innerJson = null; JObject obj; // prevents variable name shadowing - foreach (var path in schema.Path[..^1]) + foreach (var path in schemaPathSections[..^1]) { obj = innerJson ?? json; if (!obj.ContainsKey(path)) obj.Add(path, new JObject()); @@ -17,7 +18,7 @@ public static void UpdateValueWithSchema(this JObject json, TraitsSchemaData sch } // handle last path - var lastPath = schema.Path.Last(); + var lastPath = schemaPathSections.Last(); obj = innerJson ?? json; obj[lastPath] = new JValue(value); } diff --git a/OryAdmin/Models/TraitsSchemaData.cs b/OryAdmin/Models/TraitsSchemaData.cs deleted file mode 100644 index 9894f00..0000000 --- a/OryAdmin/Models/TraitsSchemaData.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Newtonsoft.Json.Schema; - -namespace OryAdmin.Models; - -public class TraitsSchemaData(JSchema schema, List path) -{ - public readonly JSchema Schema = schema; - public List Path = path; - - public override string ToString() - { - return Schema.ToString(); - } -} \ No newline at end of file diff --git a/OryAdmin/OryAdmin.csproj b/OryAdmin/OryAdmin.csproj index 26e8b1e..c4b4f29 100644 --- a/OryAdmin/OryAdmin.csproj +++ b/OryAdmin/OryAdmin.csproj @@ -21,6 +21,7 @@ + diff --git a/OryAdmin/Services/IdentitySchemaService.cs b/OryAdmin/Services/IdentitySchemaService.cs index bd80c58..ad487fc 100644 --- a/OryAdmin/Services/IdentitySchemaService.cs +++ b/OryAdmin/Services/IdentitySchemaService.cs @@ -1,62 +1,64 @@ -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Schema; -using OryAdmin.Models; +using Newtonsoft.Json.Schema; namespace OryAdmin.Services; public class IdentitySchemaService(ApiService apiService) { - private readonly Dictionary _schemaCache = new(); + private readonly Dictionary _schemaCache = new(); - public async Task GetById(string schemaId) + public async Task FetchById(string schemaId) { // check if schema object is cached if (_schemaCache.TryGetValue(schemaId, out var schema)) return schema; // request and cache new schema object var newSchema = await apiService.KratosIdentity.GetIdentitySchemaAsync(schemaId); - _schemaCache[schemaId] = (JObject)newSchema; + _schemaCache[schemaId] = JSchema.Parse(newSchema.ToString()!); return _schemaCache[schemaId]; } public async Task> ListIds() { var schemas = await apiService.KratosIdentity.ListIdentitySchemasAsync(); - foreach (var container in schemas) _schemaCache[container.Id] = (JObject)container.Schema; + foreach (var container in schemas) _schemaCache[container.Id] = JSchema.Parse(container.Schema.ToString()!); return schemas.Select(container => container.Id).ToList(); } - public async Task> GetTraitSchemas(string schemaId) + public async Task, JSchema>> GetTraits(string schemaId) + { + var schema = await FetchById(schemaId); + return GetTraits(schema); + } + + + public static Dictionary, JSchema> GetTraits(JSchema schema) { - var schemaObject = await GetById(schemaId); - var schema = JSchema.Parse(schemaObject.ToString()); var traits = schema.Properties["traits"].Properties; return FlattenTraits(traits, []); } - private static List FlattenTraits(IDictionary traits, List path) + private static Dictionary, JSchema> FlattenTraits(IDictionary traits, + IReadOnlyCollection pathSections) { - var list = new List(); + var map = new Dictionary, JSchema>(); foreach (var (traitKey, trait) in traits) { - var newPath = new List(path) { traitKey }; + var newPathSections = new List(pathSections) { traitKey }; switch (trait.Type) { - case JSchemaType.String: - list.Add(new TraitsSchemaData(trait, newPath)); - break; case JSchemaType.Object: - list.AddRange(FlattenTraits(trait.Properties, newPath)); + foreach (var entry in FlattenTraits(trait.Properties, newPathSections)) + map[entry.Key] = entry.Value; break; case JSchemaType.Array: // TODO support arrays break; - default: - list.Add(new TraitsSchemaData(trait, newPath)); + default: // string, etc. + map[newPathSections] = trait; break; } } - return list; + return map; } } \ No newline at end of file diff --git a/OryUI.sln.DotSettings b/OryUI.sln.DotSettings new file mode 100644 index 0000000..90f6839 --- /dev/null +++ b/OryUI.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file