diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepView.axaml b/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepView.axaml
new file mode 100644
index 000000000..2317f1da8
--- /dev/null
+++ b/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepView.axaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Installing default plugins and profiles, these will provide you with a basic setup to get started with Artemis.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepView.axaml.cs b/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepView.axaml.cs
new file mode 100644
index 000000000..1050a6b30
--- /dev/null
+++ b/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepView.axaml.cs
@@ -0,0 +1,14 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.ReactiveUI;
+
+namespace Artemis.UI.Screens.StartupWizard.Steps;
+
+public partial class DefaultEntriesStepView : ReactiveUserControl
+{
+ public DefaultEntriesStepView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepViewModel.cs b/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepViewModel.cs
new file mode 100644
index 000000000..d9226057a
--- /dev/null
+++ b/src/Artemis.UI/Screens/StartupWizard/Steps/DefaultEntriesStepViewModel.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Artemis.Core.Services;
+using Artemis.UI.Extensions;
+using Artemis.UI.Shared.Services;
+using Artemis.UI.Shared.Utilities;
+using Artemis.WebClient.Workshop;
+using Artemis.WebClient.Workshop.Handlers.InstallationHandlers;
+using Artemis.WebClient.Workshop.Services;
+using PropertyChanged.SourceGenerator;
+using ReactiveUI;
+using StrawberryShake;
+
+namespace Artemis.UI.Screens.StartupWizard.Steps;
+
+public partial class DefaultEntriesStepViewModel : WizardStepViewModel
+{
+ [Notify] private bool _workshopReachable;
+ [Notify] private bool _fetchingDefaultEntries;
+ [Notify] private int _totalEntries;
+ [Notify] private int _installedEntries;
+ [Notify] private int _installProgress;
+ [Notify] private IEntrySummary? _currentEntry;
+
+ private readonly IWorkshopService _workshopService;
+ private readonly IWorkshopClient _client;
+ private readonly IWindowService _windowService;
+ private readonly Progress _currentEntryProgress = new();
+
+
+ public DefaultEntriesStepViewModel(IWorkshopService workshopService, IDeviceService deviceService, IWorkshopClient client, IWindowService windowService)
+ {
+ _workshopService = workshopService;
+ _client = client;
+ _windowService = windowService;
+ _currentEntryProgress.ProgressChanged += (_, f) => InstallProgress = f.ProgressPercentage;
+
+ Continue = ReactiveCommand.Create(() => Wizard.ChangeScreen());
+ GoBack = ReactiveCommand.Create(() =>
+ {
+ if (deviceService.EnabledDevices.Count == 0)
+ Wizard.ChangeScreen();
+ else
+ Wizard.ChangeScreen();
+ });
+
+ this.WhenActivatedAsync(async d =>
+ {
+ WorkshopReachable = await _workshopService.ValidateWorkshopStatus(d.AsCancellationToken());
+ if (WorkshopReachable)
+ {
+ await InstallDefaultEntries(d.AsCancellationToken());
+ }
+ });
+ }
+
+ public async Task InstallDefaultEntries(CancellationToken cancellationToken)
+ {
+ FetchingDefaultEntries = true;
+ TotalEntries = 0;
+ InstalledEntries = 0;
+
+ if (!WorkshopReachable)
+ return false;
+
+ IOperationResult result = await _client.GetDefaultEntries.ExecuteAsync(100, null, cancellationToken);
+ List entries = result.Data?.EntriesV2?.Edges?.Select(e => e.Node).Cast().ToList() ?? [];
+ 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));
+ }
+
+ await Task.Delay(1000);
+ FetchingDefaultEntries = false;
+ TotalEntries = entries.Count;
+
+ if (entries.Count == 0)
+ return false;
+
+ foreach (IEntrySummary entry in entries)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ return false;
+
+ CurrentEntry = entry;
+
+ // Skip entries without a release and entries that are already installed
+ if (entry.LatestRelease == null || _workshopService.GetInstalledEntry(entry.Id) != null)
+ {
+ InstalledEntries++;
+ continue;
+ }
+
+ EntryInstallResult installResult = await _workshopService.InstallEntry(entry, entry.LatestRelease, _currentEntryProgress, cancellationToken);
+
+ // Unlikely as default entries do nothing fancy
+ if (!installResult.IsSuccess)
+ {
+ await _windowService.CreateContentDialog().WithTitle("Failed to install entry")
+ .WithContent($"Failed to install entry '{entry.Name}' ({entry.Id}): {installResult.Message}")
+ .WithCloseButtonText("Skip and continue")
+ .ShowAsync();
+ }
+
+ InstalledEntries++;
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/DevicesStepViewModel.cs b/src/Artemis.UI/Screens/StartupWizard/Steps/DevicesStepViewModel.cs
index ed2f364d9..1a3e15768 100644
--- a/src/Artemis.UI/Screens/StartupWizard/Steps/DevicesStepViewModel.cs
+++ b/src/Artemis.UI/Screens/StartupWizard/Steps/DevicesStepViewModel.cs
@@ -22,7 +22,7 @@ public class DevicesStepViewModel : WizardStepViewModel
Continue = ReactiveCommand.Create(() =>
{
if (deviceService.EnabledDevices.Count == 0)
- Wizard.ChangeScreen();
+ Wizard.ChangeScreen();
else
Wizard.ChangeScreen();
});
diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/SurfaceStepViewModel.cs b/src/Artemis.UI/Screens/StartupWizard/Steps/SurfaceStepViewModel.cs
index 04989be43..3ddc71021 100644
--- a/src/Artemis.UI/Screens/StartupWizard/Steps/SurfaceStepViewModel.cs
+++ b/src/Artemis.UI/Screens/StartupWizard/Steps/SurfaceStepViewModel.cs
@@ -19,7 +19,7 @@ public class SurfaceStepViewModel : WizardStepViewModel
_deviceService = deviceService;
SelectLayout = ReactiveCommand.Create(ExecuteSelectLayout);
- Continue = ReactiveCommand.Create(() => Wizard.ChangeScreen());
+ Continue = ReactiveCommand.Create(() => Wizard.ChangeScreen());
GoBack = ReactiveCommand.Create(() => Wizard.ChangeScreen());
}
@@ -30,6 +30,6 @@ public class SurfaceStepViewModel : WizardStepViewModel
// TODO: Implement the layout
_deviceService.AutoArrangeDevices();
- Wizard.ChangeScreen();
+ Wizard.ChangeScreen();
}
}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql
index ce6eedddc..3827be7ea 100644
--- a/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql
+++ b/src/Artemis.WebClient.Workshop/Queries/GetEntries.graphql
@@ -18,4 +18,20 @@ query GetPopularEntries {
popularEntries {
...entrySummary
}
+}
+
+query GetDefaultEntries($first: Int $after: String) {
+ entriesV2(where: {isDefault: {eq: true}} first: $first after: $after) {
+ totalCount
+ pageInfo {
+ hasNextPage
+ endCursor
+ }
+ edges {
+ cursor
+ node {
+ ...entrySummary
+ }
+ }
+ }
}
\ No newline at end of file