1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 13:28:33 +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"
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.ItemsPanel>

View File

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

View File

@ -16,7 +16,7 @@ public partial class CreatePersonalAccessTokenViewModel : ContentDialogViewModel
private readonly IUserManagementService _userManagementService;
private readonly IWindowService _windowService;
[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)
{
@ -25,13 +25,13 @@ public partial class CreatePersonalAccessTokenViewModel : ContentDialogViewModel
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 || 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.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 EndDate => DateTime.Today.AddDays(365);
public DateTime StartDate => DateTime.UtcNow.Date.AddDays(1);
public DateTime EndDate => DateTime.UtcNow.Date.AddDays(365);
public ReactiveCommand<Unit, Unit> Submit { get; }
private async Task ExecuteSubmit(CancellationToken cts)

View File

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

View File

@ -20,7 +20,7 @@
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Command="{CompiledBinding ViewWorkshopPage}">
<Grid ColumnDefinitions="Auto,*,*,*,Auto">
<Grid ColumnDefinitions="Auto,2*,*,*,*,Auto">
<Border Grid.Column="0"
CornerRadius="6"
VerticalAlignment="Center"
@ -42,12 +42,13 @@
</StackPanel>
<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 Text="{CompiledBinding InstalledEntry.InstalledAt, FallbackValue=01-01-1337, Mode=OneWay, Converter={StaticResource DateTimeConverter}}" />
</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 Uninstall}" Theme="{StaticResource TransparentButton}" Height="32">
<avalonia:MaterialIcon Kind="Trash"/>

View File

@ -63,6 +63,14 @@ public class PluginEntryInstallationHandler : IEntryInstallationHandler
using ZipArchive archive = new(stream);
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
try
{

View File

@ -97,7 +97,7 @@ public class InstalledEntry
/// <param name="value">The value to set.</param>
public void SetMetadata(string key, object value)
{
_metadata.Add(key, value);
_metadata[key] = value;
}
/// <summary>
@ -118,7 +118,7 @@ public class InstalledEntry
{
return new DirectoryInfo(Path.Combine(Constants.WorkshopFolder, $"{EntryId}-{StringUtilities.UrlFriendly(Name)}"));
}
/// <summary>
/// Returns the directory info of a release of this entry, where any files would be stored if applicable.
/// </summary>

View File

@ -3,7 +3,7 @@ namespace Artemis.WebClient.Workshop.Models;
public class PersonalAccessToken
{
public string Key { get; init; }
public DateTimeOffset CreationTime { get; init; }
public DateTimeOffset? Expiration { get; init; }
public DateTime CreationTime { get; init; }
public DateTime? Expiration { 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> ChangeAvatar(Stream avatar, 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<List<PersonalAccessToken>> GetPersonAccessTokens(CancellationToken cancellationToken);
}

View File

@ -66,7 +66,7 @@ internal class UserManagementService : IUserManagementService
}
/// <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);
HttpResponseMessage response = await client.PostAsync("user/access-token", JsonContent.Create(new {Description = description, ExpirationDate = expirationDate}), cancellationToken);