1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Workshop - Finished initial plugin implementation

This commit is contained in:
RobertBeekman 2024-02-17 11:54:22 +01:00
parent f2c8de1746
commit cf10193bd2
10 changed files with 70 additions and 45 deletions

View File

@ -19,7 +19,10 @@
Grid.RowSpan="3" Grid.RowSpan="3"
VerticalAlignment="Top" /> VerticalAlignment="Top" />
<TextBlock Grid.Column="1" Grid.Row="0" Classes="h5 no-margin" Text="{CompiledBinding Plugin.Info.Name}" /> <TextBlock Grid.Column="1" Grid.Row="0" Classes="no-margin">
<Run Classes="h5" Text="{CompiledBinding Plugin.Info.Name}"/>
<Run Classes="subtitle" Text="{CompiledBinding Plugin.Info.Version}"/>
</TextBlock>
<ItemsControl Grid.Column="2" Grid.Row="0" IsVisible="{CompiledBinding Platforms.Count}" ItemsSource="{CompiledBinding Platforms}" HorizontalAlignment="Right"> <ItemsControl Grid.Column="2" Grid.Row="0" IsVisible="{CompiledBinding Platforms.Count}" ItemsSource="{CompiledBinding Platforms}" HorizontalAlignment="Right">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>

View File

@ -1,7 +1,9 @@
using Artemis.UI.Shared.Extensions;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using ReactiveUI;
namespace Artemis.UI.Screens.Settings.Account; namespace Artemis.UI.Screens.Settings.Account;
@ -10,5 +12,6 @@ public partial class CreatePersonalAccessTokenView : ReactiveUserControl<CreateP
public CreatePersonalAccessTokenView() public CreatePersonalAccessTokenView()
{ {
InitializeComponent(); InitializeComponent();
this.WhenActivated(_ => this.ClearAllDataValidationErrors());
} }
} }

View File

@ -16,7 +16,7 @@ public partial class CreatePersonalAccessTokenViewModel : ContentDialogViewModel
private readonly IUserManagementService _userManagementService; private readonly IUserManagementService _userManagementService;
private readonly IWindowService _windowService; private readonly IWindowService _windowService;
[Notify] private string _description = string.Empty; [Notify] private string _description = string.Empty;
[Notify] private DateTime _expirationDate = DateTime.Today.AddDays(180); [Notify] private DateTime _expirationDate = DateTime.UtcNow.Date.AddDays(181);
public CreatePersonalAccessTokenViewModel(IUserManagementService userManagementService, IWindowService windowService) public CreatePersonalAccessTokenViewModel(IUserManagementService userManagementService, IWindowService windowService)
{ {
@ -25,13 +25,13 @@ public partial class CreatePersonalAccessTokenViewModel : ContentDialogViewModel
Submit = ReactiveCommand.CreateFromTask(ExecuteSubmit, ValidationContext.Valid); Submit = ReactiveCommand.CreateFromTask(ExecuteSubmit, ValidationContext.Valid);
this.ValidationRule(vm => vm.Description, e => e != null, "You must specify a description"); this.ValidationRule(vm => vm.Description, e => e != null, "You must specify a description");
this.ValidationRule(vm => vm.Description, e => e == null || e.Length >= 10, "You must specify a description of at least 10 characters"); this.ValidationRule(vm => vm.Description, e => e == null || e.Length >= 5, "You must specify a description of at least 5 characters");
this.ValidationRule(vm => vm.Description, e => e == null || e.Length <= 150, "You must specify a description of less than 150 characters"); this.ValidationRule(vm => vm.Description, e => e == null || e.Length <= 150, "You must specify a description of less than 150 characters");
this.ValidationRule(vm => vm.ExpirationDate, e => e >= DateTime.Today.AddDays(1), "Expiration date must be at least 24 hours from now"); this.ValidationRule(vm => vm.ExpirationDate, e => e >= DateTime.UtcNow.Date.AddDays(1), "Expiration date must be at least 24 hours from now");
} }
public DateTime StartDate => DateTime.Today.AddDays(1); public DateTime StartDate => DateTime.UtcNow.Date.AddDays(1);
public DateTime EndDate => DateTime.Today.AddDays(365); public DateTime EndDate => DateTime.UtcNow.Date.AddDays(365);
public ReactiveCommand<Unit, Unit> Submit { get; } public ReactiveCommand<Unit, Unit> Submit { get; }
private async Task ExecuteSubmit(CancellationToken cts) private async Task ExecuteSubmit(CancellationToken cts)

View File

@ -15,31 +15,31 @@
<converters:DateTimeConverter x:Key="DateTimeConverter" /> <converters:DateTimeConverter x:Key="DateTimeConverter" />
</UserControl.Resources> </UserControl.Resources>
<Panel> <Panel>
<!-- <StackPanel IsVisible="{CompiledBinding !IsLoggedIn^}" Margin="0 50 0 0"> --> <StackPanel IsVisible="{CompiledBinding !IsLoggedIn^}" Margin="0 50 0 0">
<!-- <StackPanel.Styles> --> <StackPanel.Styles>
<!-- <Styles> --> <Styles>
<!-- <Style Selector="TextBlock"> --> <Style Selector="TextBlock">
<!-- <Setter Property="TextAlignment" Value="Center"></Setter> --> <Setter Property="TextAlignment" Value="Center"></Setter>
<!-- <Setter Property="TextWrapping" Value="Wrap"></Setter> --> <Setter Property="TextWrapping" Value="Wrap"></Setter>
<!-- </Style> --> </Style>
<!-- </Styles> --> </Styles>
<!-- </StackPanel.Styles> --> </StackPanel.Styles>
<!-- <TextBlock Theme="{StaticResource TitleTextBlockStyle}">You are not logged in</TextBlock> --> <TextBlock Theme="{StaticResource TitleTextBlockStyle}">You are not logged in</TextBlock>
<!-- <TextBlock> --> <TextBlock>
<!-- <Run>In order to manage your account you must be logged in.</Run> --> <Run>In order to manage your account you must be logged in.</Run>
<!-- <LineBreak /> --> <LineBreak />
<!-- <Run>Creating an account is free and we'll not bother you with a newsletter or crap like that.</Run> --> <Run>Creating an account is free and we'll not bother you with a newsletter or crap like that.</Run>
<!-- </TextBlock> --> </TextBlock>
<!-- -->
<!-- <Lottie Path="/Assets/Animations/login-pending.json" RepeatCount="1" Width="350" Height="350"></Lottie> --> <Lottie Path="/Assets/Animations/login-pending.json" RepeatCount="1" Width="350" Height="350"></Lottie>
<!-- -->
<!-- <TextBlock> --> <TextBlock>
<!-- <Run>Click Log In below to (create an account) and log in.</Run> --> <Run>Click Log In below to (create an account) and log in.</Run>
<!-- <LineBreak /> --> <LineBreak />
<!-- <Run>You'll also be able to log in with Google or Discord.</Run> --> <Run>You'll also be able to log in with Google or Discord.</Run>
<!-- </TextBlock> --> </TextBlock>
<!-- <Button HorizontalAlignment="Center" Command="{CompiledBinding Login}" Margin="0 25 0 0">Login</Button> --> <Button HorizontalAlignment="Center" Command="{CompiledBinding Login}" Margin="0 25 0 0">Login</Button>
<!-- </StackPanel> --> </StackPanel>
<ScrollViewer IsVisible="{CompiledBinding IsLoggedIn^}" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer IsVisible="{CompiledBinding IsLoggedIn^}" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="15" MaxWidth="1000"> <StackPanel Margin="15" MaxWidth="1000">
@ -109,16 +109,26 @@
</TextBlock> </TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> <Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel> <StackPanel>
<DockPanel Margin="0 0 0 10">
<TextBlock VerticalAlignment="Center">
Tokens be used to communicate with Artemis APIs without using a username and password
</TextBlock>
<Button HorizontalAlignment="Right" Command="{CompiledBinding GenerateToken}">Generate token</Button> <Button HorizontalAlignment="Right" Command="{CompiledBinding GenerateToken}">Generate token</Button>
</DockPanel>
<Grid ColumnDefinitions="2*,*,*,*" Margin="12 6"> <Grid ColumnDefinitions="2*,*,*,*" Margin="12 6">
<TextBlock Grid.Column="0">Description</TextBlock> <TextBlock Grid.Column="0">Description</TextBlock>
<TextBlock Grid.Column="1">Created at</TextBlock> <TextBlock Grid.Column="1">Created at</TextBlock>
<TextBlock Grid.Column="2" Grid.ColumnSpan="2">Expires at</TextBlock> <TextBlock Grid.Column="2" Grid.ColumnSpan="2">Expires at</TextBlock>
</Grid> </Grid>
<ItemsControl ItemsSource="{CompiledBinding PersonalAccessTokens}"> <TextBlock IsVisible="{CompiledBinding !PersonalAccessTokens.Count}" TextAlignment="Center" Classes="subtitle" Margin="0 10">
You have no active personal access tokens.
</TextBlock>
<ItemsControl ItemsSource="{CompiledBinding PersonalAccessTokens}" IsVisible="{CompiledBinding PersonalAccessTokens.Count}">
<ItemsControl.Styles> <ItemsControl.Styles>
<Style Selector="ContentPresenter:nth-child(even) > Border"> <Style Selector="ContentPresenter:nth-child(odd) > Border">
<Setter Property="Background" Value="{StaticResource ControlStrokeColorOnAccentDefault}"></Setter> <Setter Property="Background" Value="{StaticResource ControlStrokeColorOnAccentDefault}"></Setter>
</Style> </Style>
</ItemsControl.Styles> </ItemsControl.Styles>

View File

@ -20,7 +20,7 @@
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"
Command="{CompiledBinding ViewWorkshopPage}"> Command="{CompiledBinding ViewWorkshopPage}">
<Grid ColumnDefinitions="Auto,*,*,*,Auto"> <Grid ColumnDefinitions="Auto,2*,*,*,*,Auto">
<Border Grid.Column="0" <Border Grid.Column="0"
CornerRadius="6" CornerRadius="6"
VerticalAlignment="Center" VerticalAlignment="Center"
@ -42,12 +42,13 @@
</StackPanel> </StackPanel>
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{CompiledBinding InstalledEntry.EntryType}"></TextBlock> <TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{CompiledBinding InstalledEntry.EntryType}"></TextBlock>
<TextBlock Grid.Column="3" VerticalAlignment="Center"> <TextBlock Grid.Column="3" VerticalAlignment="Center" Text="{CompiledBinding InstalledEntry.ReleaseVersion}"></TextBlock>
<TextBlock Grid.Column="4" VerticalAlignment="Center">
<Run>Installed</Run> <Run>Installed</Run>
<Run Text="{CompiledBinding InstalledEntry.InstalledAt, FallbackValue=01-01-1337, Mode=OneWay, Converter={StaticResource DateTimeConverter}}" /> <Run Text="{CompiledBinding InstalledEntry.InstalledAt, FallbackValue=01-01-1337, Mode=OneWay, Converter={StaticResource DateTimeConverter}}" />
</TextBlock> </TextBlock>
<StackPanel Grid.Column="4" VerticalAlignment="Center" Orientation="Horizontal" Spacing="6"> <StackPanel Grid.Column="5" VerticalAlignment="Center" Orientation="Horizontal" Spacing="6">
<Button Command="{CompiledBinding ViewLocal}">Open</Button> <Button Command="{CompiledBinding ViewLocal}">Open</Button>
<Button Command="{CompiledBinding Uninstall}" Theme="{StaticResource TransparentButton}" Height="32"> <Button Command="{CompiledBinding Uninstall}" Theme="{StaticResource TransparentButton}" Height="32">
<avalonia:MaterialIcon Kind="Trash"/> <avalonia:MaterialIcon Kind="Trash"/>

View File

@ -63,6 +63,14 @@ public class PluginEntryInstallationHandler : IEntryInstallationHandler
using ZipArchive archive = new(stream); using ZipArchive archive = new(stream);
archive.ExtractToDirectory(releaseDirectory.FullName); archive.ExtractToDirectory(releaseDirectory.FullName);
// If there is already a version of the plugin installed, disable it
if (installedEntry.TryGetMetadata("PluginId", out Guid pluginId))
{
Plugin? currentVersion = _pluginManagementService.GetAllPlugins().FirstOrDefault(p => p.Guid == pluginId);
if (currentVersion != null)
_pluginManagementService.UnloadPlugin(currentVersion);
}
// Load the plugin, next time during startup this will happen automatically // Load the plugin, next time during startup this will happen automatically
try try
{ {

View File

@ -97,7 +97,7 @@ public class InstalledEntry
/// <param name="value">The value to set.</param> /// <param name="value">The value to set.</param>
public void SetMetadata(string key, object value) public void SetMetadata(string key, object value)
{ {
_metadata.Add(key, value); _metadata[key] = value;
} }
/// <summary> /// <summary>

View File

@ -3,7 +3,7 @@ namespace Artemis.WebClient.Workshop.Models;
public class PersonalAccessToken public class PersonalAccessToken
{ {
public string Key { get; init; } public string Key { get; init; }
public DateTimeOffset CreationTime { get; init; } public DateTime CreationTime { get; init; }
public DateTimeOffset? Expiration { get; init; } public DateTime? Expiration { get; init; }
public string? Description { get; init; } public string? Description { get; init; }
} }

View File

@ -10,7 +10,7 @@ public interface IUserManagementService : IProtectedArtemisService
Task<ApiResult> ChangeEmailAddress(string emailAddress, CancellationToken cancellationToken); Task<ApiResult> ChangeEmailAddress(string emailAddress, CancellationToken cancellationToken);
Task<ApiResult> ChangeAvatar(Stream avatar, CancellationToken cancellationToken); Task<ApiResult> ChangeAvatar(Stream avatar, CancellationToken cancellationToken);
Task<ApiResult> RemoveAccount(CancellationToken cancellationToken); Task<ApiResult> RemoveAccount(CancellationToken cancellationToken);
Task<string> CreatePersonAccessToken(string description, DateTimeOffset expirationDate, CancellationToken cancellationToken); Task<string> CreatePersonAccessToken(string description, DateTime expirationDate, CancellationToken cancellationToken);
Task<ApiResult> DeletePersonAccessToken(PersonalAccessToken personalAccessToken, CancellationToken cancellationToken); Task<ApiResult> DeletePersonAccessToken(PersonalAccessToken personalAccessToken, CancellationToken cancellationToken);
Task<List<PersonalAccessToken>> GetPersonAccessTokens(CancellationToken cancellationToken); Task<List<PersonalAccessToken>> GetPersonAccessTokens(CancellationToken cancellationToken);
} }

View File

@ -66,7 +66,7 @@ internal class UserManagementService : IUserManagementService
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task<string> CreatePersonAccessToken(string description, DateTimeOffset expirationDate, CancellationToken cancellationToken) public async Task<string> CreatePersonAccessToken(string description, DateTime expirationDate, CancellationToken cancellationToken)
{ {
HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME); HttpClient client = _httpClientFactory.CreateClient(WorkshopConstants.IDENTITY_CLIENT_NAME);
HttpResponseMessage response = await client.PostAsync("user/access-token", JsonContent.Create(new {Description = description, ExpirationDate = expirationDate}), cancellationToken); HttpResponseMessage response = await client.PostAsync("user/access-token", JsonContent.Create(new {Description = description, ExpirationDate = expirationDate}), cancellationToken);