Better UI and Reactive Attribute

This commit is contained in:
2023-08-10 19:24:34 +02:00
parent 4dce6e3d38
commit 72f3ac90cd
6 changed files with 71 additions and 81 deletions

View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ReactiveUI />
</Weavers>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ReactiveUI" minOccurs="0" maxOccurs="1" type="xs:anyType" />
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -9,7 +9,7 @@
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
<ApplicationIcon>Assets/app.ico</ApplicationIcon> <ApplicationIcon>Assets/app.ico</ApplicationIcon>
<Version>0.0.8</Version> <Version>0.0.9</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
@@ -31,6 +31,7 @@
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.0.2" /> <PackageReference Include="Avalonia.Xaml.Interactions" Version="11.0.2" />
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.0.2" /> <PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.0.2" />
<PackageReference Include="KubernetesClient" Version="11.0.44" /> <PackageReference Include="KubernetesClient" Version="11.0.44" />
<PackageReference Include="ReactiveUI.Fody" Version="19.4.1" />
<PackageReference Include="Serilog" Version="3.0.1" /> <PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />

View File

@@ -19,6 +19,8 @@ public class FileInformation
public string Size { get; set; } = string.Empty; public string Size { get; set; } = string.Empty;
public DateTimeOffset? Date { get; set; } public DateTimeOffset? Date { get; set; }
public string DateTimeOffsetString => Date?.ToString("yyyy-MM-dd HH:mm:ss") ?? string.Empty;
public bool IsFile => Type == FileType.File; public bool IsFile => Type == FileType.File;
public bool IsDirectory => Type == FileType.Directory; public bool IsDirectory => Type == FileType.Directory;
public bool IsUnknown => Type == FileType.Unknown; public bool IsUnknown => Type == FileType.Unknown;

View File

@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using K8sFileBrowser.Models; using K8sFileBrowser.Models;
using K8sFileBrowser.Services; using K8sFileBrowser.Services;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace K8sFileBrowser.ViewModels; namespace K8sFileBrowser.ViewModels;
@@ -16,81 +17,39 @@ public class MainWindowViewModel : ViewModelBase
private ObservableAsPropertyHelper<IEnumerable<ClusterContext>> _clusterContexts = null!; private ObservableAsPropertyHelper<IEnumerable<ClusterContext>> _clusterContexts = null!;
public IEnumerable<ClusterContext> ClusterContexts => _clusterContexts.Value; public IEnumerable<ClusterContext> ClusterContexts => _clusterContexts.Value;
private ClusterContext? _selectedClusterContext; [Reactive]
public ClusterContext? SelectedClusterContext { get; set; }
public ClusterContext? SelectedClusterContext [Reactive]
{ public IEnumerable<Namespace> Namespaces { get; set; }
get => _selectedClusterContext;
set => this.RaiseAndSetIfChanged(ref _selectedClusterContext, value);
}
private IEnumerable<Namespace> _namespaces = null!; [Reactive]
public IEnumerable<Namespace> Namespaces public Namespace? SelectedNamespace { get; set; }
{
get => _namespaces;
set => this.RaiseAndSetIfChanged(ref _namespaces, value);
}
private Namespace? _selectedNamespace;
public Namespace? SelectedNamespace
{
get => _selectedNamespace;
set => this.RaiseAndSetIfChanged(ref _selectedNamespace, value);
}
private ObservableAsPropertyHelper<IEnumerable<Pod>> _pods = null!; private ObservableAsPropertyHelper<IEnumerable<Pod>> _pods = null!;
public IEnumerable<Pod> Pods => _pods.Value; public IEnumerable<Pod> Pods => _pods.Value;
private Pod? _selectedPod; [Reactive]
public Pod? SelectedPod { get; set; }
public Pod? SelectedPod [Reactive]
{ public IEnumerable<Container>? Containers { get; set; }
get => _selectedPod;
set => this.RaiseAndSetIfChanged(ref _selectedPod, value);
}
private IEnumerable<Container>? _containers;
public IEnumerable<Container>? Containers
{
get => _containers;
set => this.RaiseAndSetIfChanged(ref _containers, value);
}
private Container? _selectedContainer; [Reactive]
public Container? SelectedContainer { get; set; }
public Container? SelectedContainer
{
get => _selectedContainer;
set => this.RaiseAndSetIfChanged(ref _selectedContainer, value);
}
private ObservableAsPropertyHelper<IEnumerable<FileInformation>> _fileInformation = null!; private ObservableAsPropertyHelper<IEnumerable<FileInformation>> _fileInformation = null!;
public IEnumerable<FileInformation> FileInformation => _fileInformation.Value; public IEnumerable<FileInformation> FileInformation => _fileInformation.Value;
private FileInformation? _selectedFile; [Reactive]
public FileInformation? SelectedFile { get; set; }
public FileInformation? SelectedFile [Reactive]
{ public string? SelectedPath { get; set; }
get => _selectedFile;
set => this.RaiseAndSetIfChanged(ref _selectedFile, value);
}
private string? _selectedPath; [Reactive]
public Message Message { get; set; }
public string? SelectedPath
{
get => _selectedPath;
set => this.RaiseAndSetIfChanged(ref _selectedPath, value);
}
private Message _message = null!;
public Message Message
{
get => _message;
set => this.RaiseAndSetIfChanged(ref _message, value);
}
public ReactiveCommand<Unit, Unit> DownloadCommand { get; private set; } = null!; public ReactiveCommand<Unit, Unit> DownloadCommand { get; private set; } = null!;
public ReactiveCommand<Unit, Unit> DownloadLogCommand { get; private set; } = null!; public ReactiveCommand<Unit, Unit> DownloadLogCommand { get; private set; } = null!;
public ReactiveCommand<Unit, Unit> ParentCommand { get; private set; } = null!; public ReactiveCommand<Unit, Unit> ParentCommand { get; private set; } = null!;
@@ -143,7 +102,7 @@ public class MainWindowViewModel : ViewModelBase
.ObserveOn(RxApp.TaskpoolScheduler) .ObserveOn(RxApp.TaskpoolScheduler)
.Subscribe(_ => SelectedPath = "/"); .Subscribe(_ => SelectedPath = "/");
} }
private void RegisterReadContainers() private void RegisterReadContainers()
{ {
// read the file information when the path changes // read the file information when the path changes
@@ -155,7 +114,7 @@ public class MainWindowViewModel : ViewModelBase
: x.Item1.Containers.Select(c => new Container {Name = c})) : x.Item1.Containers.Select(c => new Container {Name = c}))
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Subscribe( x => Containers = x); .Subscribe( x => Containers = x);
this.WhenAnyValue(x => x.Containers) this.WhenAnyValue(x => x.Containers)
.Throttle(new TimeSpan(10)) .Throttle(new TimeSpan(10))
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
@@ -318,14 +277,14 @@ public class MainWindowViewModel : ViewModelBase
} }
catch (Exception e) catch (Exception e)
{ {
RxApp.MainThreadScheduler.Schedule(Action); RxApp.MainThreadScheduler.Schedule(Action);
return new List<Namespace>(); return new List<Namespace>();
async void Action() => await ShowErrorMessage(e.Message); async void Action() => await ShowErrorMessage(e.Message);
} }
} }
private IList<FileInformation> GetFileInformation(IKubernetesService kubernetesService, private IList<FileInformation> GetFileInformation(IKubernetesService kubernetesService,
string path, Pod pod, Namespace nameSpace, Container container) string path, Pod pod, Namespace nameSpace, Container container)
{ {
var kubernetesFileInformation = kubernetesService.GetFiles( var kubernetesFileInformation = kubernetesService.GetFiles(
@@ -333,7 +292,7 @@ public class MainWindowViewModel : ViewModelBase
// when the path is root, we don't want to show the parent directory // when the path is root, we don't want to show the parent directory
if (SelectedPath is not { Length: > 1 }) return kubernetesFileInformation; if (SelectedPath is not { Length: > 1 }) return kubernetesFileInformation;
// add the parent directory // add the parent directory
var parent = SelectedPath[..SelectedPath.LastIndexOf('/')]; var parent = SelectedPath[..SelectedPath.LastIndexOf('/')];
if (string.IsNullOrEmpty(parent)) if (string.IsNullOrEmpty(parent))
@@ -358,7 +317,7 @@ public class MainWindowViewModel : ViewModelBase
IsError = false IsError = false
}; };
} }
private async Task ShowErrorMessage(string message) private async Task ShowErrorMessage(string message)
{ {
Message = new Message Message = new Message
@@ -370,7 +329,7 @@ public class MainWindowViewModel : ViewModelBase
await Task.Delay(7000); await Task.Delay(7000);
HideWorkingMessage(); HideWorkingMessage();
} }
private void HideWorkingMessage() private void HideWorkingMessage()
{ {
Message = new Message Message = new Message

View File

@@ -90,7 +90,9 @@
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="10" HorizontalAlignment="Right"> <StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="10" HorizontalAlignment="Right">
<Button Command="{Binding DownloadLogCommand}" VerticalAlignment="Center" ToolTip.Tip="Download Container Log" Margin="0 0 48 0 ">
<PathIcon Data="{StaticResource document_one_page_regular}"></PathIcon>
</Button>
<Button Command="{Binding ParentCommand}" VerticalAlignment="Center" ToolTip.Tip="Go To Parent Directory"> <Button Command="{Binding ParentCommand}" VerticalAlignment="Center" ToolTip.Tip="Go To Parent Directory">
<PathIcon Data="{StaticResource arrow_curve_up_left_regular}"></PathIcon> <PathIcon Data="{StaticResource arrow_curve_up_left_regular}"></PathIcon>
</Button> </Button>
@@ -100,9 +102,6 @@
<Button Command="{Binding DownloadCommand}" VerticalAlignment="Center" ToolTip.Tip="Download File"> <Button Command="{Binding DownloadCommand}" VerticalAlignment="Center" ToolTip.Tip="Download File">
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon> <PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</Button> </Button>
<Button Command="{Binding DownloadLogCommand}" VerticalAlignment="Center" ToolTip.Tip="Download Pod Log">
<PathIcon Data="{StaticResource document_one_page_regular}"></PathIcon>
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
<DataGrid Grid.Row="1" <DataGrid Grid.Row="1"
@@ -121,11 +120,11 @@
<Setter Property="Padding" Value="10"></Setter> <Setter Property="Padding" Value="10"></Setter>
</Style> </Style>
<Style Selector="DataGridCell"> <Style Selector="DataGridCell">
<Setter Property="FontSize" Value="12"></Setter> <Setter Property="FontSize" Value="14"></Setter>
</Style> </Style>
</DataGrid.Styles> </DataGrid.Styles>
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTemplateColumn Header="Type"> <DataGridTemplateColumn Header="Type" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation"> <DataTemplate DataType="models:FileInformation">
<Border ToolTip.Tip="{Binding Type}" Background="Transparent"> <Border ToolTip.Tip="{Binding Type}" Background="Transparent">
@@ -144,7 +143,7 @@
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTemplateColumn Header="Name" Width="*"> <DataGridTemplateColumn Header="Name" Width="*" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation"> <DataTemplate DataType="models:FileInformation">
<Border Background="Transparent"> <Border Background="Transparent">
@@ -158,11 +157,11 @@
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTemplateColumn Header="Size"> <DataGridTemplateColumn Header="Size" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation"> <DataTemplate DataType="models:FileInformation">
<Border Background="Transparent"> <Border Background="Transparent">
<TextBlock Text="{Binding Size}" VerticalAlignment="Center"/> <TextBlock Text="{Binding Size}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 8 0"/>
<Interaction.Behaviors> <Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped"> <EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window }}" /> <InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window }}" />
@@ -172,14 +171,14 @@
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTemplateColumn Header="Date"> <DataGridTemplateColumn Header="Date" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation"> <DataTemplate DataType="models:FileInformation">
<Border Background="Transparent"> <Border Background="Transparent">
<TextBlock Text="{Binding Date}" VerticalAlignment="Center"/> <TextBlock Text="{Binding DateTimeOffsetString}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 8 0"/>
<Interaction.Behaviors> <Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped"> <EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window }}" /> <InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window}}" />
</EventTriggerBehavior> </EventTriggerBehavior>
</Interaction.Behaviors> </Interaction.Behaviors>
</Border> </Border>