1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-02-04 02:43:32 +00:00

Workshop - Recently updated tab

This commit is contained in:
Robert 2025-12-30 10:02:16 +01:00
parent 74d5480d7b
commit 562049681f
15 changed files with 351 additions and 101 deletions

View File

@ -100,19 +100,13 @@ public partial class DefaultEntriesStepViewModel : WizardStepViewModel
{ {
FetchingDefaultEntries = true; FetchingDefaultEntries = true;
IOperationResult<IGetDefaultEntriesResult> result = await _client.GetDefaultEntries.ExecuteAsync(100, null, cancellationToken); IOperationResult<IGetDefaultEntriesResult> result = await _client.GetDefaultEntries.ExecuteAsync(cancellationToken);
List<IEntrySummary> entries = result.Data?.EntriesV2?.Edges?.Select(e => e.Node).Cast<IEntrySummary>().ToList() ?? []; IReadOnlyList<IGetDefaultEntries_Entries> entries = result.Data?.Entries ?? [];
while (result.Data?.EntriesV2?.PageInfo is {HasNextPage: true})
{
result = await _client.GetDefaultEntries.ExecuteAsync(100, result.Data.EntriesV2.PageInfo.EndCursor, cancellationToken);
if (result.Data?.EntriesV2?.Edges != null)
entries.AddRange(result.Data.EntriesV2.Edges.Select(e => e.Node));
}
DeviceProviderEntryViewModels.Clear(); DeviceProviderEntryViewModels.Clear();
EssentialEntryViewModels.Clear(); EssentialEntryViewModels.Clear();
OtherEntryViewModels.Clear(); OtherEntryViewModels.Clear();
foreach (IEntrySummary entry in entries) foreach (IGetDefaultEntries_Entries entry in entries)
{ {
if (entry.DefaultEntryInfo == null) if (entry.DefaultEntryInfo == null)
continue; continue;

View File

@ -25,7 +25,7 @@ public partial class EntryListViewModel : RoutableScreen
private readonly SourceList<IEntrySummary> _entries = new(); private readonly SourceList<IEntrySummary> _entries = new();
private readonly INotificationService _notificationService; private readonly INotificationService _notificationService;
private readonly IWorkshopClient _workshopClient; private readonly IWorkshopClient _workshopClient;
private IGetEntries_EntriesV2_PageInfo? _currentPageInfo; private IGetEntries_PagedEntries_PageInfo? _currentPageInfo;
[Notify] private bool _initializing = true; [Notify] private bool _initializing = true;
[Notify] private bool _fetchingMore; [Notify] private bool _fetchingMore;
@ -98,11 +98,11 @@ public partial class EntryListViewModel : RoutableScreen
IOperationResult<IGetEntriesResult> entries = await _workshopClient.GetEntries.ExecuteAsync(search, IncludeDefaultEntries, filter, sort, entriesPerFetch, _currentPageInfo?.EndCursor, cancellationToken); IOperationResult<IGetEntriesResult> entries = await _workshopClient.GetEntries.ExecuteAsync(search, IncludeDefaultEntries, filter, sort, entriesPerFetch, _currentPageInfo?.EndCursor, cancellationToken);
entries.EnsureNoErrors(); entries.EnsureNoErrors();
_currentPageInfo = entries.Data?.EntriesV2?.PageInfo; _currentPageInfo = entries.Data?.PagedEntries?.PageInfo;
if (entries.Data?.EntriesV2?.Edges != null) if (entries.Data?.PagedEntries?.Edges != null)
_entries.Edit(e => e.AddRange(entries.Data.EntriesV2.Edges.Select(edge => edge.Node))); _entries.Edit(e => e.AddRange(entries.Data.PagedEntries.Edges.Select(edge => edge.Node)));
InputViewModel.TotalCount = entries.Data?.EntriesV2?.TotalCount ?? 0; InputViewModel.TotalCount = entries.Data?.PagedEntries?.TotalCount ?? 0;
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -55,8 +55,8 @@ public partial class WorkshopHomeViewModel : RoutableScreen
latest.Edit(l => latest.Edit(l =>
{ {
l.Clear(); l.Clear();
if (latestResult.Data?.EntriesV2?.Edges != null) if (latestResult.Data?.PagedEntries?.Edges != null)
l.AddRange(latestResult.Data.EntriesV2.Edges.Select(e => e.Node)); l.AddRange(latestResult.Data.PagedEntries.Edges.Select(e => e.Node));
}); });
}); });
} }

View File

@ -4,6 +4,7 @@ using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Disposables.Fluent; using System.Reactive.Disposables.Fluent;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Routing;
using Artemis.WebClient.Workshop.Models; using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Services; using Artemis.WebClient.Workshop.Services;
@ -18,6 +19,7 @@ namespace Artemis.UI.Screens.Workshop.Library.Tabs;
public partial class InstalledTabViewModel : RoutableScreen public partial class InstalledTabViewModel : RoutableScreen
{ {
private readonly IRouter _router;
private SourceList<InstalledEntry> _entries = new(); private SourceList<InstalledEntry> _entries = new();
[Notify] private string? _searchEntryInput; [Notify] private string? _searchEntryInput;
@ -25,6 +27,7 @@ public partial class InstalledTabViewModel : RoutableScreen
public InstalledTabViewModel(IWorkshopService workshopService, IRouter router, Func<InstalledEntry, InstalledTabItemViewModel> getInstalledTabItemViewModel) public InstalledTabViewModel(IWorkshopService workshopService, IRouter router, Func<InstalledEntry, InstalledTabItemViewModel> getInstalledTabItemViewModel)
{ {
_router = router;
IObservable<Func<InstalledEntry, bool>> searchFilter = this.WhenAnyValue(vm => vm.SearchEntryInput) IObservable<Func<InstalledEntry, bool>> searchFilter = this.WhenAnyValue(vm => vm.SearchEntryInput)
.Throttle(TimeSpan.FromMilliseconds(100)) .Throttle(TimeSpan.FromMilliseconds(100))
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
@ -47,8 +50,6 @@ public partial class InstalledTabViewModel : RoutableScreen
workshopService.OnEntryUninstalled += WorkshopServiceOnOnEntryUninstalled; workshopService.OnEntryUninstalled += WorkshopServiceOnOnEntryUninstalled;
Disposable.Create(() => workshopService.OnEntryUninstalled -= WorkshopServiceOnOnEntryUninstalled).DisposeWith(d); Disposable.Create(() => workshopService.OnEntryUninstalled -= WorkshopServiceOnOnEntryUninstalled).DisposeWith(d);
}); });
OpenWorkshop = ReactiveCommand.CreateFromTask(async () => await router.Navigate("workshop"));
} }
private void WorkshopServiceOnOnEntryUninstalled(object? sender, InstalledEntry e) private void WorkshopServiceOnOnEntryUninstalled(object? sender, InstalledEntry e)
@ -57,9 +58,13 @@ public partial class InstalledTabViewModel : RoutableScreen
} }
public bool Empty => _empty.Value; public bool Empty => _empty.Value;
public ReactiveCommand<Unit, Unit> OpenWorkshop { get; }
public ReadOnlyObservableCollection<IGrouping<InstalledTabItemViewModel, string>> EntryGroups { get; } public ReadOnlyObservableCollection<IGrouping<InstalledTabItemViewModel, string>> EntryGroups { get; }
public async Task OpenWorkshop()
{
await _router.Navigate("workshop");
}
private Func<InstalledEntry, bool> CreatePredicate(string? text) private Func<InstalledEntry, bool> CreatePredicate(string? text)
{ {
if (string.IsNullOrWhiteSpace(text)) if (string.IsNullOrWhiteSpace(text))

View File

@ -3,8 +3,87 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs" xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Library.Tabs"
xmlns:il="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:mdxaml="https://github.com/whistyun/Markdown.Avalonia.Tight"
xmlns:ui="clr-namespace:Artemis.UI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.RecentlyUpdatedItemView" x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.RecentlyUpdatedItemView"
x:DataType="tabs:RecentlyUpdatedItemViewModel"> x:DataType="tabs:RecentlyUpdatedItemViewModel">
Welcome to Avalonia! <UserControl.Resources>
<converters:EntryIconUriConverter x:Key="EntryIconUriConverter" />
<converters:DateTimeConverter x:Key="DateTimeConverter" />
<ui:ArtemisLinkCommand x:Key="ArtemisLinkCommand" />
</UserControl.Resources>
<Border MinHeight="110"
MaxHeight="140"
Padding="12"
HorizontalAlignment="Stretch"
Classes="card">
<Grid ColumnDefinitions="Auto,*" RowDefinitions="Auto, Auto">
<StackPanel Grid.Column="0" Grid.Row="0" Orientation="Horizontal">
<!-- Icon -->
<Border CornerRadius="6"
VerticalAlignment="Center"
Margin="0 0 2 0"
Width="20"
Height="20"
ClipToBounds="True">
<Image Stretch="UniformToFill" il:ImageLoader.Source="{CompiledBinding Entry.Id, Converter={StaticResource EntryIconUriConverter}, Mode=OneWay}" />
</Border>
<!-- Title -->
<TextBlock Margin="0 0 0 5" TextTrimming="CharacterEllipsis">
<Run Classes="h5" Text="{CompiledBinding Entry.Name, FallbackValue=Title}" />
<Run Classes="subtitle">by</Run>
<Run Classes="subtitle" Text="{CompiledBinding Entry.Author, FallbackValue=Author}" />
</TextBlock>
<avalonia:MaterialIcon
IsVisible="{CompiledBinding Entry.IsOfficial}"
Kind="ShieldStar"
Foreground="{DynamicResource SystemAccentColorLight1}"
Margin="2 -2 0 0"
Width="18"
Height="18"
HorizontalAlignment="Left"
ToolTip.Tip="Official entry by the Artemis team" />
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="0">
<!-- Info -->
<StackPanel Margin="0 0 4 0" HorizontalAlignment="Right">
<TextBlock TextAlignment="Right">
<avalonia:MaterialIcon Kind="Harddisk" />
<Run Text="{CompiledBinding Release.Version}" />
</TextBlock>
</StackPanel>
<!-- Install state -->
<StackPanel Margin="0 0 4 0" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<TextBlock TextAlignment="Right" IsVisible="{CompiledBinding NotYetInstalled}">
<avalonia:MaterialIcon Kind="Update" Foreground="{DynamicResource SystemAccentColorLight1}" Width="20" Height="20" />
<Run>not yet installed</Run>
</TextBlock>
</StackPanel>
</StackPanel>
<Panel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2">
<TextBlock Classes="subtitle" IsVisible="{CompiledBinding Release.Changelog, Converter={x:Static StringConverters.IsNullOrEmpty}}">
There are no release notes for this release.
</TextBlock>
<mdxaml:MarkdownScrollViewer Markdown="{CompiledBinding Release.Changelog}"
MarkdownStyleName="FluentAvalonia"
IsVisible="{CompiledBinding Release.Changelog, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
<mdxaml:MarkdownScrollViewer.Engine>
<mdxaml:Markdown HyperlinkCommand="{StaticResource ArtemisLinkCommand}" />
</mdxaml:MarkdownScrollViewer.Engine>
<mdxaml:MarkdownScrollViewer.Styles>
<StyleInclude Source="/Styles/Markdown.axaml" />
</mdxaml:MarkdownScrollViewer.Styles>
</mdxaml:MarkdownScrollViewer>
</Panel>
</Grid>
</Border>
</UserControl> </UserControl>

View File

@ -1,8 +1,23 @@
using Artemis.UI.Shared; using System;
using Artemis.UI.Shared;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Services;
namespace Artemis.UI.Screens.Workshop.Library.Tabs; namespace Artemis.UI.Screens.Workshop.Library.Tabs;
public partial class RecentlyUpdatedItemViewModel : ActivatableViewModelBase public partial class RecentlyUpdatedItemViewModel : ActivatableViewModelBase
{ {
public IGetRecentUpdates_Entries Entry { get; }
public IGetRecentUpdates_Entries_LatestRelease Release { get; }
public InstalledEntry InstalledEntry { get; }
public RecentlyUpdatedItemViewModel(IGetRecentUpdates_Entries entry, IWorkshopService workshopService)
{
Entry = entry;
Release = entry.LatestRelease ?? throw new InvalidOperationException("Entry does not have a latest release");
InstalledEntry = workshopService.GetInstalledEntry(entry.Id) ?? throw new InvalidOperationException("Entry is not installed");
}
public bool NotYetInstalled => InstalledEntry.ReleaseId < Release.Id;
} }

View File

@ -6,5 +6,46 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.RecentlyUpdatedView" x:Class="Artemis.UI.Screens.Workshop.Library.Tabs.RecentlyUpdatedView"
x:DataType="tabs:RecentlyUpdatedViewModel"> x:DataType="tabs:RecentlyUpdatedViewModel">
Welcome to Avalonia! <UserControl.Styles>
<Styles>
<Style Selector="StackPanel.empty-state > TextBlock">
<Setter Property="TextAlignment" Value="Center"></Setter>
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</Styles>
</UserControl.Styles>
<Grid RowDefinitions="Auto,*">
<Grid Grid.Row="0" Grid.Column="0" MaxWidth="1000" Margin="0 22 0 10">
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="165" MaxWidth="400" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Classes="search-box" Text="{CompiledBinding SearchEntryInput}" Watermark="Search updates" Margin="0 0 10 0" />
</Grid>
<StackPanel Grid.Row="1" Grid.Column="0" IsVisible="{CompiledBinding Empty}" Margin="0 50 0 0" Classes="empty-state">
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Looks like nothing updated in the last 30 days</TextBlock>
<TextBlock>
<Run>Any entries you download that recently received updates will show up here</Run>
</TextBlock>
<!-- <Lottie Path="/Assets/Animations/empty.json" RepeatCount="1" Width="350" Height="350"></Lottie> -->
<Button HorizontalAlignment="Center" Command="{CompiledBinding OpenWorkshop}">Browse the Workshop</Button>
</StackPanel>
<ScrollViewer Grid.Row="1" Grid.Column="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" VerticalAlignment="Top">
<ItemsControl ItemsSource="{CompiledBinding Entries}" Margin="0 0 20 0" MaxWidth="1000">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{CompiledBinding}" Margin="0 0 0 8"></ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl> </UserControl>

View File

@ -2,7 +2,7 @@
namespace Artemis.UI.Screens.Workshop.Library.Tabs; namespace Artemis.UI.Screens.Workshop.Library.Tabs;
public partial class RecentlyUpdatedView : ReactiveUserControl<InstalledTabViewModel> public partial class RecentlyUpdatedView : ReactiveUserControl<RecentlyUpdatedViewModel>
{ {
public RecentlyUpdatedView() public RecentlyUpdatedView()
{ {

View File

@ -1,8 +1,112 @@
using Artemis.UI.Shared.Routing; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Artemis.UI.Extensions;
using Artemis.UI.Shared.Routing;
using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Models;
using Artemis.WebClient.Workshop.Services;
using DynamicData;
using DynamicData.Aggregation;
using DynamicData.Binding;
using PropertyChanged.SourceGenerator;
using ReactiveUI;
using StrawberryShake;
namespace Artemis.UI.Screens.Workshop.Library.Tabs; namespace Artemis.UI.Screens.Workshop.Library.Tabs;
public partial class RecentlyUpdatedViewModel : RoutableScreen public partial class RecentlyUpdatedViewModel : RoutableScreen
{ {
private readonly IWorkshopService _workshopService;
private readonly IWorkshopClient _client;
private readonly IRouter _router;
private readonly SourceCache<IGetRecentUpdates_Entries, long> _entries;
private readonly ObservableAsPropertyHelper<bool> _empty;
[Notify] private bool _isLoading = true;
[Notify] private bool _workshopReachable;
[Notify] private string? _searchEntryInput;
public RecentlyUpdatedViewModel(IWorkshopService workshopService,
IWorkshopClient client,
IRouter router,
Func<IGetRecentUpdates_Entries, RecentlyUpdatedItemViewModel> getRecentlyUpdatedItemViewModel)
{
IObservable<Func<IGetRecentUpdates_Entries, bool>> searchFilter = this.WhenAnyValue(vm => vm.SearchEntryInput)
.Throttle(TimeSpan.FromMilliseconds(100))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(CreatePredicate);
_workshopService = workshopService;
_client = client;
_router = router;
_entries = new SourceCache<IGetRecentUpdates_Entries, long>(e => e.Id);
_entries.Connect()
.Filter(searchFilter)
.Transform(getRecentlyUpdatedItemViewModel)
.SortAndBind(
out ReadOnlyObservableCollection<RecentlyUpdatedItemViewModel> entries,
SortExpressionComparer<RecentlyUpdatedItemViewModel>.Descending(p => p.Release.CreatedAt)
)
.Subscribe();
_empty = _entries.Connect().Count().Select(c => c == 0).ToProperty(this, vm => vm.Empty);
Entries = entries;
this.WhenActivatedAsync(async d =>
{
WorkshopReachable = await workshopService.ValidateWorkshopStatus(true, d.AsCancellationToken());
if (WorkshopReachable)
await GetEntries(d.AsCancellationToken());
});
}
public bool Empty => _empty.Value;
public ReadOnlyObservableCollection<RecentlyUpdatedItemViewModel> Entries { get; }
public async Task OpenWorkshop()
{
await _router.Navigate("workshop");
}
private async Task GetEntries(CancellationToken ct)
{
IsLoading = true;
try
{
List<InstalledEntry> installedEntries = _workshopService.GetInstalledEntries();
IOperationResult<IGetRecentUpdatesResult> result = await _client.GetRecentUpdates.ExecuteAsync(
installedEntries.Select(e => e.Id).ToList(),
DateTimeOffset.Now.AddDays(-30).ToUniversalTime(),
ct);
if (result.Data?.Entries == null)
_entries.Clear();
else
_entries.Edit(e =>
{
e.Clear();
e.AddOrUpdate(result.Data.Entries);
});
}
finally
{
IsLoading = false;
}
}
private Func<IGetRecentUpdates_Entries, bool> CreatePredicate(string? text)
{
if (string.IsNullOrWhiteSpace(text))
return _ => true;
return data => data.Name.Contains(text, StringComparison.InvariantCultureIgnoreCase);
}
} }

View File

@ -34,7 +34,7 @@ public partial class PluginDescriptionViewModel : RoutableScreen
if (entry != null) if (entry != null)
{ {
IReadOnlyList<IEntrySummary>? dependants = (await _client.GetDependantEntries.ExecuteAsync(entry.Id, 0, 25, cancellationToken)).Data?.Entries?.Items; IReadOnlyList<IEntrySummary>? dependants = (await _client.GetDependantEntries.ExecuteAsync(entry.Id, cancellationToken)).Data?.Entries;
Dependants = dependants != null && dependants.Any() ? dependants.Select(_getEntryListViewModel).OrderByDescending(d => d.Entry.Downloads).Take(10).ToList() : null; Dependants = dependants != null && dependants.Any() ? dependants.Select(_getEntryListViewModel).OrderByDescending(d => d.Entry.Downloads).Take(10).ToList() : null;
} }
else else

View File

@ -57,17 +57,11 @@ public static class BuiltInPluginsMigrator
} }
logger.Information("MigrateBuiltInPlugins - Migrating built-in plugins to workshop entries"); logger.Information("MigrateBuiltInPlugins - Migrating built-in plugins to workshop entries");
IOperationResult<IGetDefaultPluginsResult> result = await workshopClient.GetDefaultPlugins.ExecuteAsync(100, null, CancellationToken.None); IOperationResult<IGetDefaultPluginsResult> result = await workshopClient.GetDefaultPlugins.ExecuteAsync(CancellationToken.None);
List<IGetDefaultPlugins_EntriesV2_Edges_Node> entries = result.Data?.EntriesV2?.Edges?.Select(e => e.Node).ToList() ?? []; IReadOnlyList<IGetDefaultPlugins_Entries> entries = result.Data?.Entries ?? [];
while (result.Data?.EntriesV2?.PageInfo is {HasNextPage: true})
{
result = await workshopClient.GetDefaultPlugins.ExecuteAsync(100, result.Data.EntriesV2.PageInfo.EndCursor, CancellationToken.None);
if (result.Data?.EntriesV2?.Edges != null)
entries.AddRange(result.Data.EntriesV2.Edges.Select(e => e.Node));
}
logger.Information("MigrateBuiltInPlugins - Found {Count} default plugins in the workshop", entries.Count); logger.Information("MigrateBuiltInPlugins - Found {Count} default plugins in the workshop", entries.Count);
foreach (IGetDefaultPlugins_EntriesV2_Edges_Node entry in entries) foreach (IGetDefaultPlugins_Entries entry in entries)
{ {
// Skip entries without plugin info or releases, shouldn't happen but theoretically possible // Skip entries without plugin info or releases, shouldn't happen but theoretically possible
if (entry.PluginInfo == null || entry.LatestRelease == null) if (entry.PluginInfo == null || entry.LatestRelease == null)

View File

@ -1,15 +1,10 @@
query GetDependantEntries($entryId: Long! $skip: Int $take: Int) { query GetDependantEntries($entryId: Long!) {
entries( entries(
where: { where: {
latestRelease: { dependencies: { some: { id: { eq: $entryId } } } } latestRelease: { dependencies: { some: { id: { eq: $entryId } } } }
} }
skip: $skip
take: $take
order: { createdAt: DESC } order: { createdAt: DESC }
) { ) {
totalCount
items {
...entrySummary ...entrySummary
} }
} }
}

View File

@ -1,5 +1,5 @@
query GetEntries($search: String $includeDefaults: Boolean $filter: EntryFilterInput $order: [EntrySortInput!] $first: Int $after: String) { query GetEntries($search: String $includeDefaults: Boolean $filter: EntryFilterInput $order: [EntrySortInput!] $first: Int $after: String) {
entriesV2(search: $search includeDefaults: $includeDefaults where: $filter order: $order first: $first after: $after) { pagedEntries(search: $search includeDefaults: $includeDefaults where: $filter order: $order first: $first after: $after) {
totalCount totalCount
pageInfo { pageInfo {
hasNextPage hasNextPage
@ -20,29 +20,17 @@ query GetPopularEntries {
} }
} }
query GetDefaultEntries($first: Int, $after: String) { query GetDefaultEntries {
entriesV2( entries(
includeDefaults: true includeDefaults: true
where: { defaultEntryInfo: { entryId: { gt: 0 } } } where: { defaultEntryInfo: { entryId: { gt: 0 } } }
first: $first
after: $after
) { ) {
totalCount
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
...entrySummary ...entrySummary
} }
} }
}
}
query GetDefaultPlugins($first: Int, $after: String) { query GetDefaultPlugins {
entriesV2( entries(
includeDefaults: true includeDefaults: true
where: { where: {
and: [ and: [
@ -50,22 +38,34 @@ query GetDefaultPlugins($first: Int, $after: String) {
{ entryType: {eq: PLUGIN} } { entryType: {eq: PLUGIN} }
] ]
} }
first: $first
after: $after
) { ) {
totalCount
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
...entrySummary ...entrySummary
pluginInfo { pluginInfo {
pluginGuid 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
}
} }
} }

View File

@ -4,10 +4,10 @@ public static class WorkshopConstants
{ {
// This is so I can never accidentally release with localhost // This is so I can never accidentally release with localhost
#if DEBUG #if DEBUG
// public const string AUTHORITY_URL = "https://localhost:5001"; public const string AUTHORITY_URL = "https://localhost:5001";
// public const string WORKSHOP_URL = "https://localhost:7281"; public const string WORKSHOP_URL = "https://localhost:7281";
public const string AUTHORITY_URL = "https://identity.artemis-rgb.com"; // public const string AUTHORITY_URL = "https://identity.artemis-rgb.com";
public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com"; // public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com";
#else #else
public const string AUTHORITY_URL = "https://identity.artemis-rgb.com"; public const string AUTHORITY_URL = "https://identity.artemis-rgb.com";
public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com"; public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com";

View File

@ -24,15 +24,6 @@ type DefaultEntryInfo {
isDeviceProvider: Boolean! isDeviceProvider: Boolean!
} }
"A segment of a collection."
type EntriesCollectionSegment {
"Information to aid in pagination."
pageInfo: CollectionSegmentInfo!
"A flattened list of the items."
items: [Entry!]
totalCount: Int! @cost(weight: "10")
}
"A connection to a list of items." "A connection to a list of items."
type EntriesV2Connection { type EntriesV2Connection {
"Information to aid in pagination." "Information to aid in pagination."
@ -134,6 +125,26 @@ type PageInfo {
endCursor: String endCursor: String
} }
"A connection to a list of items."
type PagedEntriesConnection {
"Information to aid in pagination."
pageInfo: PageInfo!
"A list of edges."
edges: [PagedEntriesEdge!]
"A flattened list of the nodes."
nodes: [Entry!]
"Identifies the total count of items in the connection."
totalCount: Int! @cost(weight: "10")
}
"An edge in a connection."
type PagedEntriesEdge {
"A cursor for use in pagination."
cursor: String!
"The item at the end of the edge."
node: Entry!
}
type PluginInfo { type PluginInfo {
entryId: Long! entryId: Long!
entry: Entry! entry: Entry!
@ -162,21 +173,10 @@ type Query {
where: CategoryFilterInput @cost(weight: "10") where: CategoryFilterInput @cost(weight: "10")
): [Category!]! @cost(weight: "10") ): [Category!]! @cost(weight: "10")
entries( entries(
skip: Int
take: Int
search: String
includeDefaults: Boolean includeDefaults: Boolean
order: [EntrySortInput!] @cost(weight: "10") order: [EntrySortInput!] @cost(weight: "10")
where: EntryFilterInput @cost(weight: "10") where: EntryFilterInput @cost(weight: "10")
): EntriesCollectionSegment ): [Entry!]! @cost(weight: "10")
@listSize(
assumedSize: 100
slicingArguments: ["take"]
slicingArgumentDefaultValue: 10
sizedFields: ["items"]
requireOneSlicingArgument: false
)
@cost(weight: "10")
entriesV2( entriesV2(
search: String search: String
includeDefaults: Boolean includeDefaults: Boolean
@ -199,6 +199,29 @@ type Query {
requireOneSlicingArgument: false requireOneSlicingArgument: false
) )
@cost(weight: "10") @cost(weight: "10")
@deprecated(reason: "Use GetPagedEntries with offset paging instead")
pagedEntries(
search: String
includeDefaults: Boolean
"Returns the first _n_ elements from the list."
first: Int
"Returns the elements in the list that come after the specified cursor."
after: String
"Returns the last _n_ elements from the list."
last: Int
"Returns the elements in the list that come before the specified cursor."
before: String
order: [EntrySortInput!] @cost(weight: "10")
where: EntryFilterInput @cost(weight: "10")
): PagedEntriesConnection
@listSize(
assumedSize: 100
slicingArguments: ["first", "last"]
slicingArgumentDefaultValue: 10
sizedFields: ["edges", "nodes"]
requireOneSlicingArgument: false
)
@cost(weight: "10")
entry(id: Long!): Entry @cost(weight: "10") entry(id: Long!): Entry @cost(weight: "10")
submittedEntries( submittedEntries(
order: [EntrySortInput!] @cost(weight: "10") order: [EntrySortInput!] @cost(weight: "10")