diff --git a/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs b/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs index c98a0d6df..95f16b5cb 100644 --- a/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs +++ b/src/Artemis.UI.Windows/Providers/WindowsUpdateNotificationProvider.cs @@ -175,7 +175,7 @@ public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider else if (action == "disable-workshop-notifications") _workshopUpdateService.DisableNotifications(); else if (action == "view-library") - NavigateToRoute("workshop/library"); + NavigateToRoute("workshop/library/recently-updated"); } private void NavigateToRoute(string route) diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Details/EntryInfoViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/Details/EntryInfoViewModel.cs index 13703c684..38b10e17d 100644 --- a/src/Artemis.UI/Screens/Workshop/Entries/Details/EntryInfoViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Entries/Details/EntryInfoViewModel.cs @@ -39,7 +39,7 @@ public partial class EntryInfoViewModel : ActivatableViewModelBase .DisposeWith(d); }); - IsAdministrator = authenticationService.GetRoles().Contains("Administrator"); + IsAdministrator = authenticationService.Roles.Contains("Administrator"); } public bool IsAdministrator { get; } diff --git a/src/Artemis.UI/Screens/Workshop/Entries/Details/EntrySpecificationsViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/Details/EntrySpecificationsViewModel.cs index 446e32067..08a744f93 100644 --- a/src/Artemis.UI/Screens/Workshop/Entries/Details/EntrySpecificationsViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Entries/Details/EntrySpecificationsViewModel.cs @@ -69,7 +69,7 @@ public partial class EntrySpecificationsViewModel : ValidatableViewModelBase _categoriesValid = categoriesRule.ValidationChanged.Select(c => c.IsValid).ToProperty(this, vm => vm.CategoriesValid); _descriptionValid = descriptionRule.ValidationChanged.Select(c => c.IsValid).ToProperty(this, vm => vm.DescriptionValid); - IsAdministrator = authenticationService.GetRoles().Contains("Administrator"); + IsAdministrator = authenticationService.Roles.Contains("Administrator"); this.WhenActivatedAsync(async _ => await PopulateCategories()); this.WhenAnyValue(vm => vm.Fit).Subscribe(_ => UpdateIcon()); } diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml index 0f1598426..a4856478f 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml @@ -8,6 +8,7 @@ xmlns:converters="clr-namespace:Artemis.UI.Converters" xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight" xmlns:ui="clr-namespace:Artemis.UI" + xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.RecentlyUpdatedItemView" x:DataType="tabs:RecentlyUpdatedItemViewModel"> @@ -16,27 +17,43 @@ - + + + + + - - + - - + + by @@ -44,46 +61,54 @@ IsVisible="{CompiledBinding Entry.IsOfficial}" Kind="ShieldStar" Foreground="{DynamicResource SystemAccentColorLight1}" - Margin="2 -2 0 0" + Margin="0 -2 0 0" Width="18" Height="18" HorizontalAlignment="Left" ToolTip.Tip="Official entry by the Artemis team" /> - - - - - - - - - - - - - - not yet installed - - + + + + - - - - There are no release notes for this release. - - - - - - - - - - + + + + + + + + + + + + There are no release notes for this release. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml.cs index 2896638d6..5cebd4123 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml.cs +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedItemView.axaml.cs @@ -1,4 +1,8 @@ -using ReactiveUI.Avalonia; +using System.Threading.Tasks; +using Artemis.WebClient.Workshop; +using Avalonia.Controls; +using Avalonia.Input; +using ReactiveUI.Avalonia; namespace Artemis.UI.Screens.Workshop.Library.Tabs; @@ -8,4 +12,15 @@ public partial class RecentlyUpdatedItemView : ReactiveUserControl r.Id == entry.LatestReleaseId); + NotYetInstalled = InstalledEntry.ReleaseId != Releases.Max(r => r.Id); } - public bool NotYetInstalled => InstalledEntry.ReleaseId < Release.Id; + + public InstalledEntry InstalledEntry { get; } + public IGetRecentUpdates_Entries Entry { get; } + public IReadOnlyList Releases { get; set; } + public IGetRecentUpdates_Entries_Releases LatestRelease { get; } + + public async Task NavigateToEntry() + { + await _workshopService.NavigateToEntry(Entry.Id, Entry.EntryType); + } + + public async Task NavigateToRelease(IGetRecentUpdates_Entries_Releases? release) + { + if (release == null) + return; + + await _router.Navigate($"workshop/entries/{Entry.EntryType.ToString()}s/details/{Entry.Id}/releases/{release.Id}"); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedView.axaml b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedView.axaml index b64fb619d..1fc1f6c2a 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedView.axaml +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedView.axaml @@ -15,8 +15,8 @@ - - + + @@ -34,7 +34,7 @@ - + diff --git a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedViewModel.cs index 2dc398dff..11cb140d8 100644 --- a/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedViewModel.cs +++ b/src/Artemis.UI/Screens/Workshop/Library/Tabs/RecentlyUpdatedViewModel.cs @@ -51,7 +51,7 @@ public partial class RecentlyUpdatedViewModel : RoutableScreen .Transform(getRecentlyUpdatedItemViewModel) .SortAndBind( out ReadOnlyObservableCollection entries, - SortExpressionComparer.Descending(p => p.Release.CreatedAt) + SortExpressionComparer.Descending(p => p.LatestRelease.CreatedAt) ) .Subscribe(); diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql index d9d95c3b8..d2bc3507e 100644 --- a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql +++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql @@ -44,28 +44,4 @@ query GetDefaultPlugins { pluginGuid } } -} - -query GetRecentUpdates($entryIds: [Long!]!, $cutoff: DateTime!) { - entries( - includeDefaults: true - where: { - and: [ - { id: { in: $entryIds } } - { latestRelease: { createdAt: { gte: $cutoff } } } - ] - } - ) { - id - author - isOfficial - name - summary - entryType - createdAt - latestRelease { - ...release - changelog - } - } } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Queries/GetRecentUpdates.graphql b/src/Artemis.WebClient.Workshop/Queries/GetRecentUpdates.graphql new file mode 100644 index 000000000..17bf9d845 --- /dev/null +++ b/src/Artemis.WebClient.Workshop/Queries/GetRecentUpdates.graphql @@ -0,0 +1,27 @@ +query GetRecentUpdates($entryIds: [Long!]!, $cutoff: DateTime!) { + entries( + includeDefaults: true + order: [{ latestRelease: { createdAt: DESC } }] + where: { + and: [ + { id: { in: $entryIds } } + { releases: { some: { createdAt: { gte: $cutoff } } } } + ] + } + ) { + id + author + isOfficial + name + summary + entryType + latestReleaseId + releases( + order: [{ createdAt: DESC }] + where: { createdAt: { gte: $cutoff } } + ) { + ...release + changelog + } + } +} \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs index 3f7e65735..3182f5c03 100644 --- a/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs +++ b/src/Artemis.WebClient.Workshop/Services/AuthenticationService.cs @@ -23,7 +23,8 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi private readonly IAuthenticationRepository _authenticationRepository; private readonly SemaphoreSlim _authLock = new(1, 1); private readonly SourceList _claims; - + private readonly SourceList _roles; + private readonly IDiscoveryCache _discoveryCache; private readonly ILogger _logger; private readonly IHttpClientFactory _httpClientFactory; @@ -41,7 +42,10 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi _claims = new SourceList(); _claims.Connect().Bind(out ReadOnlyObservableCollection claims).Subscribe(); + _roles = new SourceList(); + _roles.Connect().Bind(out ReadOnlyObservableCollection roles).Subscribe(); Claims = claims; + Roles = roles; } private async Task GetDiscovery() @@ -68,6 +72,11 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi c.Clear(); c.AddRange(token.Claims); }); + _roles.Edit(r => + { + r.Clear(); + r.AddRange(_claims.Items.Where(c => c.Type == JwtClaimTypes.Role).Select(c => c.Value)); + }); _isLoggedInSubject.OnNext(true); } @@ -118,7 +127,10 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi /// public ReadOnlyObservableCollection Claims { get; } - + + /// + public ReadOnlyObservableCollection Roles { get; } + /// public IObservable GetClaim(string type) { @@ -278,6 +290,7 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi _token = null; _claims.Clear(); + _roles.Clear(); SetStoredRefreshToken(null); _isLoggedInSubject.OnNext(false); } @@ -289,12 +302,6 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi return emailVerified?.Value.ToLower() == "true"; } - /// - public List GetRoles() - { - return Claims.Where(c => c.Type == JwtClaimTypes.Role).Select(c => c.Value).ToList(); - } - private async Task InternalAutoLogin(bool force = false) { if (!force && _isLoggedInSubject.Value) diff --git a/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs b/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs index 66e1392be..b698ebca6 100644 --- a/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs +++ b/src/Artemis.WebClient.Workshop/Services/Interfaces/IAuthenticationService.cs @@ -8,6 +8,7 @@ public interface IAuthenticationService : IProtectedArtemisService { IObservable IsLoggedIn { get; } ReadOnlyObservableCollection Claims { get; } + ReadOnlyObservableCollection Roles { get; } IObservable GetClaim(string type); Task GetBearer(); @@ -15,5 +16,4 @@ public interface IAuthenticationService : IProtectedArtemisService Task Login(CancellationToken cancellationToken); Task Logout(); bool GetIsEmailVerified(); - List GetRoles(); } \ No newline at end of file diff --git a/src/Artemis.WebClient.Workshop/schema.graphql b/src/Artemis.WebClient.Workshop/schema.graphql index e20b76968..06d063edf 100644 --- a/src/Artemis.WebClient.Workshop/schema.graphql +++ b/src/Artemis.WebClient.Workshop/schema.graphql @@ -65,7 +65,10 @@ type Entry { categories: [Category!]! tags: [Tag!]! images: [Image!]! - releases: [Release!]! + releases( + order: [ReleaseSortInput!] @cost(weight: "10") + where: ReleaseFilterInput @cost(weight: "10") + ): [Release!]! dependantReleases: [Release!]! }