14 Commits

Author SHA1 Message Date
6223e982d7 bump version 2025-03-13 06:20:00 +01:00
07912b3239 improved the context menu 2025-03-13 06:19:04 +01:00
249e74eb7b .gitignore 2025-03-13 03:22:11 +01:00
9926c26cc3 fixed nuke build 2025-03-13 03:21:23 +01:00
f12b12a82c Build for Windows, MacOs and Linux (#11)
* macosx build
* update to .net8 and newest nugets
* added context menu to file list
* update version number
2025-03-13 03:04:42 +01:00
d405677420 Merge pull request #10 from frosch95/pr-9
Refresh button for the file list
2023-10-09 20:30:31 +02:00
0e979fad5f Closes #9 : Refresh button for the file list 2023-10-09 20:29:40 +02:00
6754210e9b Merge pull request #7 from frosch95/pr-6
Sort properties in alphabatically order
2023-10-05 14:37:30 +02:00
0d11fdd000 Closes #6 Sort properties in alphabatically order 2023-10-05 14:22:18 +02:00
b33552531a remember last chosen local directory 2023-08-28 20:26:41 +02:00
7f7471d47b show message also in ui thread 2023-08-14 20:30:25 +02:00
6d03c88261 reworked the whole reactive property handling 2023-08-12 00:31:37 +02:00
a696152667 fix broken build 2023-08-11 14:31:07 +02:00
491127d460 fix broken path selection 2023-08-11 14:30:20 +02:00
31 changed files with 663 additions and 400 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ riderModule.iml
/_ReSharper.Caches/
.idea/
*.user
.nuke/temp

View File

@@ -1,19 +1,48 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"$ref": "#/definitions/build",
"title": "Build Schema",
"definitions": {
"build": {
"type": "object",
"Host": {
"type": "string",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
},
"ExecutableTarget": {
"type": "string",
"enum": [
"Clean",
"Publish",
"PublishLinux",
"PublishOsx",
"PublishWin"
]
},
"Verbosity": {
"type": "string",
"description": "",
"enum": [
"Verbose",
"Normal",
"Minimal",
"Quiet"
]
},
"NukeBuild": {
"properties": {
"Configuration": {
"type": "string",
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
"enum": [
"Debug",
"Release"
]
},
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
@@ -23,25 +52,8 @@
"description": "Shows the help text for this build assembly"
},
"Host": {
"type": "string",
"description": "Host for execution. Default is 'automatic'",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
"$ref": "#/definitions/Host"
},
"NoLogo": {
"type": "boolean",
@@ -70,44 +82,41 @@
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
"type": "string",
"enum": [
"Clean",
"Publish",
"PublishLinux",
"PublishWin",
"Restore"
]
"$ref": "#/definitions/ExecutableTarget"
}
},
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",
"items": {
"type": "string",
"enum": [
"Clean",
"Publish",
"PublishLinux",
"PublishWin",
"Restore"
]
"$ref": "#/definitions/ExecutableTarget"
}
},
"Verbosity": {
"type": "string",
"description": "Logging verbosity during build execution. Default is 'Normal'",
"$ref": "#/definitions/Verbosity"
}
}
}
},
"allOf": [
{
"properties": {
"Configuration": {
"type": "string",
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
"enum": [
"Minimal",
"Normal",
"Quiet",
"Verbose"
"Debug",
"Release"
]
},
"Version": {
"type": "string"
}
}
},
{
"$ref": "#/definitions/NukeBuild"
}
}
]
}

BIN
Assets/.DS_Store vendored Normal file

Binary file not shown.

BIN
Assets/favicon_io.zip Normal file

Binary file not shown.

BIN
Assets/favicon_io/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
This favicon was generated using the following font:
- Font Title: Genos
- Font Author: Copyright 2011 The Genos Project Authors (https://github.com/googlefonts/genos)
- Font Source: http://fonts.gstatic.com/s/genos/v12/SlGNmQqPqpUOYTYjacb0Hc91fTwVA0_orUK6K7ZsAg.ttf
- Font License: SIL Open Font License, 1.1 (http://scripts.sil.org/OFL))

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@@ -12,6 +12,7 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C0C29CAE-A5C1-43B8-BFF8-BFE718FE04E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0C29CAE-A5C1-43B8-BFF8-BFE718FE04E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C0C29CAE-A5C1-43B8-BFF8-BFE718FE04E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{637A753B-3168-4C9C-8098-7A16024E1957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{637A753B-3168-4C9C-8098-7A16024E1957}.Debug|Any CPU.Build.0 = Debug|Any CPU
{637A753B-3168-4C9C-8098-7A16024E1957}.Release|Any CPU.ActiveCfg = Release|Any CPU

BIN
K8sFileBrowser/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -10,7 +10,7 @@
</Application.DataTemplates>
<Application.Styles>
<FluentTheme>
<FluentTheme DensityStyle="Compact">
<FluentTheme.Palettes>
<!-- Palette for Light theme variant -->
<ColorPaletteResources x:Key="Light" Accent="Green" RegionColor="White" ErrorText="Red" />
@@ -20,7 +20,7 @@
Accent="#677696"
RegionColor="#282c34"
ErrorText="Red"
AltHigh="#282c34"
AltHigh="#343a45"
AltMediumLow="#2c313c"
ListLow="#21252b"
ListMedium="#2c313c"
@@ -29,6 +29,7 @@
ChromeMediumLow="#21252b"
/>
<!-- AltHigh is used for the color of header in the DataGrid -->
<!-- BaseHigh is used for the text color -->
<!-- ListLow is used for the mouse over in lists and DataGrid -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
@@ -9,8 +9,8 @@
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
<ApplicationIcon>Assets/app.ico</ApplicationIcon>
<Version>0.0.9</Version>
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
<Version>0.1.4</Version>
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE</DefineConstants>
@@ -22,21 +22,21 @@
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.2" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.2" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.2" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.2" />
<PackageReference Include="Avalonia" Version="11.2.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.5" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.5" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.5" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.2" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.2" />
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.0.2" />
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.0.2" />
<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.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.5" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.5" />
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.2.0.14" />
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.2.0.14" />
<PackageReference Include="KubernetesClient" Version="16.0.2" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageReference Include="Serilog" Version="4.2.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.ReactiveUI;
using System;
using Avalonia.Logging;
using Serilog;
namespace K8sFileBrowser;
@@ -18,6 +19,7 @@ class Program
//.Filter.ByIncludingOnly(Matching.WithProperty("Area", LogArea.Control))
.MinimumLevel.Information()
.WriteTo.Async(a => a.File("app.log"))
//.WriteTo.Console()
.CreateLogger();
BuildAvaloniaApp()
@@ -42,5 +44,6 @@ class Program
.UsePlatformDetect()
.WithInterFont()
.LogToTrace()
//.LogToTrace(LogEventLevel.Verbose)
.UseReactiveUI();
}

View File

@@ -1,19 +1,28 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading.Tasks;
using K8sFileBrowser.Models;
using K8sFileBrowser.Services;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Serilog;
namespace K8sFileBrowser.ViewModels;
public class MainWindowViewModel : ViewModelBase
{
#region Properties
[Reactive]
public string? Version { get; set; }
[Reactive]
public IEnumerable<ClusterContext> ClusterContexts { get; set; } = null!;
@@ -50,22 +59,31 @@ public class MainWindowViewModel : ViewModelBase
[Reactive]
public Message Message { get; set; } = null!;
public ReactiveCommand<Unit, Unit> DownloadCommand { 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> OpenCommand { get; private set; } = null!;
private string _lastDirectory = ".";
#endregion Properties
#region Commands
public ReactiveCommand<Unit, Unit> DownloadLogCommand { get; private set; } = null!;
public ReactiveCommand<Unit, Unit> RefreshCommand { get; private set; } = null!;
public ReactiveCommand<Unit, Unit> ParentCommand { get; private set; } = null!;
public ReactiveCommand<FileInformation, Unit> OpenContextCommand { get; private set; } = null!;
public ReactiveCommand<FileInformation, Unit> DownloadContextCommand { get; private set; } = null!;
private ReactiveCommand<Namespace, IEnumerable<Pod>> GetPodsForNamespace { get; set; } = null!;
#endregion Commands
public MainWindowViewModel()
{
//TODO: use dependency injection to get the kubernetes service
IKubernetesService kubernetesService = new KubernetesService();
Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
// commands
ConfigureOpenDirectoryCommand();
ConfigureDownloadFileCommand(kubernetesService);
ConfigureOpenDirectoryContextCommand();
ConfigureDownloadFileContextCommand(kubernetesService);
ConfigureRefreshCommand(kubernetesService);
ConfigureDownloadLogCommand(kubernetesService);
ConfigureParentDirectoryCommand();
ConfigureGetPodsForNamespaceCommand(kubernetesService);
@@ -81,6 +99,8 @@ public class MainWindowViewModel : ViewModelBase
InitiallyLoadContexts(kubernetesService);
}
#region Property Subscriptions
private void InitiallyLoadContexts(IKubernetesService kubernetesService)
{
// load the cluster contexts when the view model is created
@@ -91,70 +111,12 @@ public class MainWindowViewModel : ViewModelBase
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x =>
{
ClusterContexts = x;
ResetNamespaces();
ClusterContexts = x.OrderBy(c => c.Name);
// select the current cluster context
SelectedClusterContext = ClusterContexts
.FirstOrDefault(x => x.Name == kubernetesService.GetCurrentContext());
});
}
private void RegisterResetPath()
{
// reset the path when the pod or namespace changes
this.WhenAnyValue(c => c.SelectedContainer)
.Throttle(new TimeSpan(10))
.ObserveOn(RxApp.TaskpoolScheduler)
.Subscribe(_ => SelectedPath = "/");
}
private void RegisterReadContainers()
{
// read the file information when the path changes
this
.WhenAnyValue(c => c.SelectedPod)
.Throttle(new TimeSpan(10))
.Select(x => x == null
? new List<Container>()
: x.Containers.Select(c => new Container {Name = c}))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe( x =>
{
Containers = x;
FileInformation = new List<FileInformation>();
});
this.WhenAnyValue(x => x.Containers)
.Throttle(new TimeSpan(10))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x => SelectedContainer = x?.FirstOrDefault());
}
private void RegisterReadFiles(IKubernetesService kubernetesService)
{
// read the file information when the path changes
this
.WhenAnyValue(c => c.SelectedContainer)
.Throttle(new TimeSpan(10))
.Select(x => x == null
? new List<FileInformation>()
: GetFileInformation(kubernetesService, SelectedPath!, SelectedPod!, SelectedNamespace!, x))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x => FileInformation = x);
}
private void RegisterReadPods()
{
// read the pods when the namespace changes
this
.WhenAnyValue(c => c.SelectedNamespace)
.Throttle(new TimeSpan(10))
.SelectMany(ns => GetPodsForNamespace.Execute(ns!))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x =>
{
Pods = x;
Containers = null;
FileInformation = new List<FileInformation>();
.FirstOrDefault(c => c.Name == kubernetesService.GetCurrentContext());
});
}
@@ -168,20 +130,80 @@ public class MainWindowViewModel : ViewModelBase
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ns =>
{
Namespaces = ns;
Pods = new List<Pod>();
Containers = null;
FileInformation = new List<FileInformation>();
ResetPods();
Namespaces = ns.OrderBy(n => n.Name);
});
}
private void RegisterReadPods()
{
// read the pods when the namespace changes
this
.WhenAnyValue(c => c.SelectedNamespace)
.Throttle(new TimeSpan(10))
.Where(x => x != null)
.SelectMany(ns => GetPodsForNamespace.Execute(ns!))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x =>
{
ResetContainers();
Pods = x.OrderBy(p => p.Name);
});
}
private void RegisterReadContainers()
{
// read the file information when the path changes
this
.WhenAnyValue(c => c.SelectedPod)
.Throttle(new TimeSpan(10))
.Where(x => x != null)
.Select(x => x!.Containers.Select(c => new Container {Name = c}))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe( x =>
{
ResetPath();
Containers = x;
});
this.WhenAnyValue(x => x.Containers)
.Throttle(new TimeSpan(10))
.Where(x => x != null && x.Any())
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x => SelectedContainer = x?.FirstOrDefault());
}
private void RegisterResetPath()
{
// reset the path when the pod or namespace changes
this.WhenAnyValue(c => c.SelectedContainer)
.Throttle(new TimeSpan(10))
.Where(x => x != null)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(_ => SelectedPath = "/");
}
private void RegisterReadFiles(IKubernetesService kubernetesService)
{
// read the file information when the path changes
this
.WhenAnyValue(c => c.SelectedContainer, c => c.SelectedPath)
.Throttle(new TimeSpan(10))
.Where(x => x is { Item1: not null, Item2: not null })
.Select(x => GetFileInformation(kubernetesService, x.Item2!, SelectedPod!, SelectedNamespace!, x.Item1!))
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x => FileInformation = x);
}
#endregion Property Subscriptions
#region Configure Commands
private void ConfigureGetPodsForNamespaceCommand(IKubernetesService kubernetesService)
{
GetPodsForNamespace = ReactiveCommand.CreateFromObservable<Namespace, IEnumerable<Pod>>(ns =>
Observable.StartAsync(_ => PodsAsync(ns, kubernetesService), RxApp.TaskpoolScheduler));
GetPodsForNamespace.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
.Subscribe(ShowErrorMessage);
}
private void ConfigureParentDirectoryCommand()
@@ -200,7 +222,7 @@ public class MainWindowViewModel : ViewModelBase
}, isNotRoot, RxApp.MainThreadScheduler);
ParentCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
.Subscribe(ShowErrorMessage);
}
private void ConfigureDownloadLogCommand(IKubernetesService kubernetesService)
@@ -214,9 +236,10 @@ public class MainWindowViewModel : ViewModelBase
await Observable.StartAsync(async () =>
{
var fileName = SelectedPod?.Name + ".log";
var saveFileName = await ApplicationHelper.SaveFile(".", fileName);
var saveFileName = await ApplicationHelper.SaveFile(_lastDirectory, fileName);
if (saveFileName != null)
{
SetLastDirectory(saveFileName);
ShowWorkingMessage("Downloading Log...");
await kubernetesService.DownloadLog(SelectedNamespace, SelectedPod, SelectedContainer, saveFileName);
HideWorkingMessage();
@@ -225,54 +248,74 @@ public class MainWindowViewModel : ViewModelBase
}, isSelectedPod, RxApp.MainThreadScheduler);
DownloadLogCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
.Subscribe(ShowErrorMessage);
}
private void ConfigureDownloadFileCommand(IKubernetesService kubernetesService)
private void ConfigureRefreshCommand(IKubernetesService kubernetesService)
{
var isFile = this
.WhenAnyValue(x => x.SelectedFile, x => x.Message.IsVisible)
.Select(x => x is { Item1.Type: FileType.File, Item2: false });
var isSelectedContainer = this
.WhenAnyValue(x => x.SelectedContainer)
.Select(x => x != null);
DownloadCommand = ReactiveCommand.CreateFromTask(async () =>
RefreshCommand = ReactiveCommand.CreateFromTask(async () =>
{
await Observable.Start(() =>
{
FileInformation = GetFileInformation(kubernetesService, SelectedPath!, SelectedPod!, SelectedNamespace!, SelectedContainer!);
}, RxApp.TaskpoolScheduler);
}, isSelectedContainer, RxApp.MainThreadScheduler);
RefreshCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ShowErrorMessage);
}
private void ConfigureDownloadFileContextCommand(IKubernetesService kubernetesService)
{
DownloadContextCommand = ReactiveCommand.CreateFromTask<FileInformation>(async (file) =>
{
await Observable.StartAsync(async () =>
{
var fileName = SelectedFile!.Name.Substring(SelectedFile!.Name.LastIndexOf('/') + 1,
SelectedFile!.Name.Length - SelectedFile!.Name.LastIndexOf('/') - 1);
var saveFileName = await ApplicationHelper.SaveFile(".", fileName);
var fileName = file.Name.Substring(SelectedFile!.Name.LastIndexOf('/') + 1,
file.Name.Length - file.Name.LastIndexOf('/') - 1);
var saveFileName = await ApplicationHelper.SaveFile(_lastDirectory, fileName);
if (saveFileName != null)
{
SetLastDirectory(saveFileName);
ShowWorkingMessage("Downloading File...");
await kubernetesService.DownloadFile(SelectedNamespace, SelectedPod, SelectedContainer, SelectedFile, saveFileName);
await kubernetesService.DownloadFile(SelectedNamespace, SelectedPod, SelectedContainer, file, saveFileName);
HideWorkingMessage();
}
}, RxApp.TaskpoolScheduler);
}, isFile, RxApp.MainThreadScheduler);
}, outputScheduler: RxApp.MainThreadScheduler);
DownloadCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
DownloadContextCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ShowErrorMessage);
}
private void ConfigureOpenDirectoryCommand()
private void SetLastDirectory(string saveFileName)
{
var isDirectory = this
.WhenAnyValue(x => x.SelectedFile, x => x.Message.IsVisible)
.Select(x => x is { Item1.Type: FileType.Directory, Item2: false });
OpenCommand = ReactiveCommand.Create(() =>
{
if (".." == SelectedFile?.Name)
SelectedPath = SelectedFile?.Parent;
else
SelectedPath = SelectedFile != null ? SelectedFile!.Name : "/";
},
isDirectory, RxApp.MainThreadScheduler);
OpenCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
_lastDirectory = saveFileName.Substring(0, saveFileName.LastIndexOf(Path.DirectorySeparatorChar));
}
private void ConfigureOpenDirectoryContextCommand()
{
OpenContextCommand = ReactiveCommand.Create<FileInformation>((file) =>
{
SelectedPath = ".." == file.Name ? file.Parent : file.Name;
}, outputScheduler: RxApp.MainThreadScheduler);
OpenContextCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(ShowErrorMessage);
}
#endregion Configure Commands
#region Get Data
private static async Task<IEnumerable<Pod>> PodsAsync(Namespace? ns, IKubernetesService kubernetesService)
{
if (ns == null)
@@ -296,10 +339,8 @@ public class MainWindowViewModel : ViewModelBase
}
catch (Exception e)
{
RxApp.MainThreadScheduler.Schedule(Action);
ShowErrorMessage(e);
return new List<Namespace>();
async void Action() => await ShowErrorMessage(e.Message);
}
}
@@ -327,35 +368,89 @@ public class MainWindowViewModel : ViewModelBase
}).ToList();
}
private void ShowWorkingMessage(string message)
#endregion Get Data
#region Reset Data
private void ResetPath()
{
Message = new Message
{
IsVisible = true,
Text = message,
IsError = false
};
FileInformation = new List<FileInformation>();
SelectedPath = null;
SelectedContainer = null;
}
private async Task ShowErrorMessage(string message)
private void ResetContainers()
{
Message = new Message
ResetPath();
Containers = new List<Container>();
SelectedPod = null;
}
private void ResetPods()
{
ResetContainers();
SelectedNamespace = null;
Pods = new List<Pod>();
}
private void ResetNamespaces()
{
ResetPods();
Namespaces = new List<Namespace>();
SelectedClusterContext = null;
}
#endregion Reset Data
#region show messages
private void ShowWorkingMessage(string message)
{
RxApp.MainThreadScheduler.Schedule(Action);
return;
void Action()
{
IsVisible = true,
Text = message,
IsError = true
};
await Task.Delay(7000);
HideWorkingMessage();
Message = new Message
{
IsVisible = true,
Text = message,
IsError = false
};
}
}
private void ShowErrorMessage(string message)
{
RxApp.MainThreadScheduler.Schedule(Action);
return;
async void Action()
{
Message = new Message { IsVisible = true, Text = message, IsError = true };
await Task.Delay(7000);
HideWorkingMessage();
}
}
private void ShowErrorMessage(Exception exception)
{
// ReSharper disable once TemplateIsNotCompileTimeConstantProblem
Log.Error(exception, exception.Message);
ShowErrorMessage(exception.Message);
}
private void HideWorkingMessage()
{
Message = new Message
RxApp.MainThreadScheduler.Schedule(() => Message = new Message
{
IsVisible = false,
Text = "",
IsError = false
};
});
}
#endregion show messages
}

View File

@@ -15,180 +15,300 @@
</Design.DataContext>
<Grid>
<Border ZIndex="1" IsVisible="{Binding Message.IsVisible}" Background="{Binding Message.Color}" Opacity="{Binding Message.Opacity}">
<Border ZIndex="1" IsVisible="{Binding Message.IsVisible}" Background="{Binding Message.Color}"
Opacity="{Binding Message.Opacity}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Spacing="20" MaxWidth="500">
<PathIcon Classes="loading" Data="{StaticResource arrow_rotate_clockwise_regular}" Width="100" Height="100" IsVisible="{Binding !Message.IsError}"></PathIcon>
<PathIcon Data="{StaticResource warning_regular}" Width="100" Height="100" IsVisible="{Binding Message.IsError}"></PathIcon>
<PathIcon Classes="loading" Data="{StaticResource arrow_rotate_clockwise_regular}" Width="100"
Height="100" IsVisible="{Binding !Message.IsError}">
</PathIcon>
<PathIcon Data="{StaticResource warning_regular}" Width="100" Height="100"
IsVisible="{Binding Message.IsError}">
</PathIcon>
<TextBlock TextWrapping="Wrap" Text="{Binding Message.Text}">.</TextBlock>
</StackPanel>
</Border>
<Grid RowDefinitions="Auto, *">
<Border Padding="10 14" Background="#21252b">
<Grid ColumnDefinitions="Auto,Auto,Auto,*">
<Label Grid.Column="0"
VerticalAlignment="Center"
Margin="0 0 10 0">
Cluster:
</Label>
<ComboBox Grid.Column="1"
ItemsSource="{Binding ClusterContexts}"
SelectedItem="{Binding SelectedClusterContext}"
VerticalAlignment="Center"
MinWidth="200"
Margin="0 0 10 0">
</ComboBox>
<Label Grid.Column="2"
VerticalAlignment="Center"
Margin="0 0 10 0">
Namespace:
</Label>
<ComboBox Grid.Column="3"
ItemsSource="{Binding Namespaces}"
SelectedItem="{Binding SelectedNamespace}"
VerticalAlignment="Center"
MinWidth="200"
Margin="0 0 10 0">
</ComboBox>
</Grid>
</Border>
<Grid ColumnDefinitions="*, 1, 3*" Grid.Row="1">
<ListBox
ItemsSource="{Binding Pods}"
SelectedItem="{Binding SelectedPod}" Background="Transparent">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="0" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="0" Padding="0 4 0 4" BorderBrush="SlateGray"
BorderThickness="0 0 0 1">
<TextBlock Text="{Binding}" Padding="4" Margin="4" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<GridSplitter Grid.Column="1" ResizeDirection="Columns" />
<Grid Grid.Column="2" RowDefinitions="Auto, *">
<Grid ColumnDefinitions="*, Auto, Auto">
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="Current Directory" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
<TextBlock Text="{Binding SelectedPath}" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
<Label VerticalAlignment="Center"
Margin="0 0 10 0">
Container:
</Label>
<ComboBox ItemsSource="{Binding Containers}"
SelectedItem="{Binding SelectedContainer}"
VerticalAlignment="Center"
MinWidth="200"
Margin="0 0 10 0">
</ComboBox>
</StackPanel>
<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">
<PathIcon Data="{StaticResource arrow_curve_up_left_regular}"></PathIcon>
</Button>
<Button Command="{Binding OpenCommand}" VerticalAlignment="Center" ToolTip.Tip="Browse Directory">
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
</Button>
<Button Command="{Binding DownloadCommand}" VerticalAlignment="Center" ToolTip.Tip="Download File">
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</Button>
</StackPanel>
<Border Padding="10 14" Background="#21252b">
<Grid ColumnDefinitions="Auto,Auto,Auto,*,Auto">
<Label Grid.Column="0"
VerticalAlignment="Center"
Margin="0 0 10 0">
Cluster:
</Label>
<ComboBox Grid.Column="1"
ItemsSource="{Binding ClusterContexts}"
SelectedItem="{Binding SelectedClusterContext}"
VerticalAlignment="Center"
MinWidth="200"
Margin="0 0 10 0">
</ComboBox>
<Label Grid.Column="2"
VerticalAlignment="Center"
Margin="0 0 10 0">
Namespace:
</Label>
<ComboBox Grid.Column="3"
ItemsSource="{Binding Namespaces}"
SelectedItem="{Binding SelectedNamespace}"
VerticalAlignment="Center"
MinWidth="200"
Margin="0 0 10 0">
</ComboBox>
<TextBlock Grid.Column="4" HorizontalAlignment="Right" VerticalAlignment="Center"
Text="{Binding Version}" />
</Grid>
</Border>
<Grid ColumnDefinitions="*, 1, 3*" Grid.Row="1">
<ListBox
ItemsSource="{Binding Pods}"
SelectedItem="{Binding SelectedPod}" Background="Transparent">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="0" />
</Style>
</ListBox.Styles>
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="0" Padding="0 4 0 4" BorderBrush="SlateGray"
BorderThickness="0 0 0 1">
<TextBlock Text="{Binding}" Padding="4" Margin="4" />
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<GridSplitter Grid.Column="1" ResizeDirection="Columns" />
<Grid Grid.Column="2" RowDefinitions="Auto, *">
<Grid ColumnDefinitions="*, Auto, Auto">
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="Current Directory" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
<TextBlock Text="{Binding SelectedPath}" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
<Label VerticalAlignment="Center"
Margin="0 0 10 0">
Container:
</Label>
<ComboBox ItemsSource="{Binding Containers}"
SelectedItem="{Binding SelectedContainer}"
VerticalAlignment="Center"
MinWidth="200"
Margin="0 0 10 0">
</ComboBox>
</StackPanel>
<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 RefreshCommand}" VerticalAlignment="Center"
ToolTip.Tip="Refresh Directory">
<PathIcon Data="{StaticResource arrow_sync_circle_regular}"></PathIcon>
</Button>
<Button Command="{Binding ParentCommand}" VerticalAlignment="Center"
ToolTip.Tip="Go To Parent Directory">
<PathIcon Data="{StaticResource arrow_curve_up_left_regular}"></PathIcon>
</Button>
<Button Command="{Binding OpenContextCommand}" CommandParameter="{Binding SelectedFile}"
IsEnabled="{Binding SelectedFile.IsDirectory}" VerticalAlignment="Center"
ToolTip.Tip="Browse Directory">
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
</Button>
<Button Command="{Binding DownloadContextCommand}"
CommandParameter="{Binding SelectedFile}" IsEnabled="{Binding SelectedFile.IsFile}"
VerticalAlignment="Center" ToolTip.Tip="Download File">
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</Button>
</StackPanel>
</Grid>
<DataGrid Grid.Row="1"
Name="FileInformationDataGrid"
Margin="2 0 2 0"
ItemsSource="{Binding FileInformation}"
IsReadOnly="True"
GridLinesVisibility="Horizontal"
BorderThickness="1"
SelectionMode="Single"
SelectedItem="{Binding SelectedFile}"
Focusable="False">
<DataGrid.Styles>
<Style Selector="DataGridColumnHeader">
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="Padding" Value="10"></Setter>
</Style>
<Style Selector="DataGridCell">
<Setter Property="FontSize" Value="14"></Setter>
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border ToolTip.Tip="{Binding Type}" Background="Transparent">
<Border.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Open"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Download"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).DownloadContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsFile}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Border.ContextFlyout>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<PathIcon Data="{StaticResource folder_regular}"
IsVisible="{Binding IsDirectory}">
</PathIcon>
<PathIcon Data="{StaticResource document_regular}"
IsVisible="{Binding IsFile}">
</PathIcon>
<PathIcon Data="{StaticResource document_error_regular}"
IsVisible="{Binding IsSymbolicLink}">
</PathIcon>
<PathIcon Data="{StaticResource document_unknown_regular}"
IsVisible="{Binding IsUnknown}">
</PathIcon>
</StackPanel>
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}"/>
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Name" Width="*" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border Background="Transparent">
<Border.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Open"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Download"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).DownloadContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsFile}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Border.ContextFlyout>
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center" />
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}"/>
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Size" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border Background="Transparent">
<Border.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Open"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Download"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).DownloadContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsFile}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Border.ContextFlyout>
<TextBlock Text="{Binding Size}" VerticalAlignment="Center"
HorizontalAlignment="Right" Margin="0 0 10 0" />
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}"/>
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Date" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border Background="Transparent">
<Border.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Open"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Download"
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).DownloadContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsFile}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Border.ContextFlyout>
<TextBlock Text="{Binding DateTimeOffsetString}" VerticalAlignment="Center"
Margin="10 0 8 0" />
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction
Command="{Binding $parent[Window].((vm:MainWindowViewModel)DataContext).OpenContextCommand}"
CommandParameter="{Binding}"
IsEnabled="{Binding IsDirectory}"/>
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
<DataGrid Grid.Row="1"
Name="FileInformationDataGrid"
Margin="2 0 2 0"
ItemsSource="{Binding FileInformation}"
IsReadOnly="True"
GridLinesVisibility="Horizontal"
BorderThickness="1"
SelectionMode="Single"
SelectedItem="{Binding SelectedFile}"
Focusable="False">
<DataGrid.Styles>
<Style Selector="DataGridColumnHeader">
<Setter Property="FontSize" Value="14"></Setter>
<Setter Property="Padding" Value="10"></Setter>
</Style>
<Style Selector="DataGridCell">
<Setter Property="FontSize" Value="14"></Setter>
</Style>
</DataGrid.Styles>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border ToolTip.Tip="{Binding Type}" Background="Transparent">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<PathIcon Data="{StaticResource folder_regular}" IsVisible="{Binding IsDirectory}"></PathIcon>
<PathIcon Data="{StaticResource document_regular}" IsVisible="{Binding IsFile}"></PathIcon>
<PathIcon Data="{StaticResource document_error_regular}" IsVisible="{Binding IsSymbolicLink}"></PathIcon>
<PathIcon Data="{StaticResource document_unknown_regular}" IsVisible="{Binding IsUnknown}"></PathIcon>
</StackPanel>
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window }}" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Name" Width="*" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border Background="Transparent">
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center"/>
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window }}" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Size" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border Background="Transparent">
<TextBlock Text="{Binding Size}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 0 10 0"/>
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window }}" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Date" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="models:FileInformation">
<Border Background="Transparent">
<TextBlock Text="{Binding DateTimeOffsetString}" VerticalAlignment="Center" Margin="10 0 8 0"/>
<Interaction.Behaviors>
<EventTriggerBehavior EventName="DoubleTapped">
<InvokeCommandAction Command="{Binding ((vm:MainWindowViewModel)DataContext).OpenCommand, RelativeSource={RelativeSource AncestorType=Window}}" />
</EventTriggerBehavior>
</Interaction.Behaviors>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
</Grid>
</Grid>
</Window>

View File

@@ -3,7 +3,7 @@
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="K8sFileBrowser.Desktop"/>
<assemblyIdentity version="1.4.0.0" name="K8sFileBrowser.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>

View File

@@ -12,15 +12,17 @@ class Build : NukeBuild
[Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]
readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
[Parameter] readonly string Version = "1.0.0";
[Parameter] readonly string Version = "1.5.0";
AbsolutePath SourceDirectory => RootDirectory / "K8sFileBrowser";
AbsolutePath OutputDirectory => RootDirectory / "output";
AbsolutePath WinOutputDirectory => OutputDirectory / "win";
AbsolutePath LinuxOutputDirectory => OutputDirectory / "linux";
AbsolutePath OsxOutputDirectory => OutputDirectory / "osx";
AbsolutePath WinZip => OutputDirectory / $"K8sFileBrowser_{Version}.zip";
AbsolutePath LinuxGz => OutputDirectory / $"K8sFileBrowser_{Version}.tgz";
AbsolutePath OsxGz => OutputDirectory / $"K8sFileBrowser_OSX_{Version}.tgz";
AbsolutePath ProjectFile => SourceDirectory / "K8sFileBrowser.csproj";
@@ -31,20 +33,11 @@ class Build : NukeBuild
Target Clean => _ => _
.Before(Restore)
.Executes(() =>
{
OutputDirectory.DeleteDirectory();
});
Target Restore => _ => _
.Executes(() =>
{
DotNet($"restore {ProjectFile}");
//DotNetTasks.DotNetRestore(new DotNetRestoreSettings());
});
Target PublishWin => _ => _
.DependsOn(Clean)
.Executes(() =>
@@ -53,17 +46,16 @@ class Build : NukeBuild
.SetProject(ProjectFile)
.SetConfiguration(Configuration)
.SetOutput(WinOutputDirectory)
.SetSelfContained(true)
.SetFramework("net7.0")
.EnableSelfContained()
.SetFramework("net8.0")
.SetRuntime("win-x64")
.SetPublishSingleFile(true)
.SetPublishReadyToRun(true)
.EnablePublishSingleFile()
.EnablePublishReadyToRun()
.SetAuthors("Andreas Billmann")
.SetCopyright("Copyright (c) 2023")
.SetVersion(Version)
.SetProcessArgumentConfigurator(_ => _
.Add("-p:IncludeNativeLibrariesForSelfExtract=true"))
.EnableNoRestore());
.Add("-p:IncludeNativeLibrariesForSelfExtract=true")));
WinOutputDirectory.ZipTo(
WinZip,
@@ -73,24 +65,23 @@ class Build : NukeBuild
});
Target PublishLinux => _ => _
.DependsOn(Clean)
.DependsOn(Clean)
.Executes(() =>
{
DotNetPublish(s => s
.SetProject(ProjectFile)
.SetConfiguration(Configuration)
.SetOutput(LinuxOutputDirectory)
.SetSelfContained(true)
.SetFramework("net7.0")
.EnableSelfContained()
.SetFramework("net8.0")
.SetRuntime("linux-x64")
.SetPublishSingleFile(true)
.SetPublishReadyToRun(true)
.EnablePublishSingleFile()
.EnablePublishReadyToRun()
.SetAuthors("Andreas Billmann")
.SetCopyright("Copyright (c) 2023")
.SetVersion(Version)
.SetProcessArgumentConfigurator(_ => _
.Add("-p:IncludeNativeLibrariesForSelfExtract=true"))
.EnableNoRestore());
.Add("-p:IncludeNativeLibrariesForSelfExtract=true")));
LinuxOutputDirectory.TarGZipTo(
LinuxGz,
@@ -98,8 +89,33 @@ class Build : NukeBuild
fileMode: FileMode.CreateNew);
});
Target PublishOsx => _ => _
.DependsOn(Clean)
.Executes(() =>
{
DotNetPublish(s => s
.SetProject(ProjectFile)
.SetConfiguration(Configuration)
.SetOutput(OsxOutputDirectory)
.EnableSelfContained()
.SetFramework("net8.0")
.SetRuntime("osx-arm64")
.EnablePublishSingleFile()
.EnablePublishReadyToRun()
.SetAuthors("Andreas Billmann")
.SetCopyright("Copyright (c) 2023")
.SetVersion(Version)
.SetProcessArgumentConfigurator(_ => _
.Add("-p:IncludeNativeLibrariesForSelfExtract=true")));
OsxOutputDirectory.TarGZipTo(
OsxGz,
filter: x => !x.HasExtension(ExcludedExtensions),
fileMode: FileMode.CreateNew);
});
Target Publish => _ => _
.DependsOn(PublishWin, PublishLinux)
.DependsOn(PublishWin, PublishLinux, PublishOsx)
.Executes(() =>
{
});

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace></RootNamespace>
<NoWarn>CS0649;CS0169</NoWarn>
<NukeRootDirectory>..</NukeRootDirectory>
@@ -11,7 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nuke.Common" Version="7.0.2" />
<PackageReference Include="Nuke.Common" Version="8.1.4" />
</ItemGroup>
</Project>

View File

@@ -17,6 +17,8 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
@@ -25,4 +27,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

7
global.json Normal file
View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "8.0.0",
"rollForward": "latestFeature",
"allowPrerelease": false
}
}