Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6223e982d7 | |||
| 07912b3239 | |||
| 249e74eb7b | |||
| 9926c26cc3 | |||
| f12b12a82c | |||
| d405677420 | |||
| 0e979fad5f | |||
| 6754210e9b | |||
| 0d11fdd000 | |||
| b33552531a | |||
| 7f7471d47b | |||
| 6d03c88261 | |||
| a696152667 | |||
| 491127d460 | |||
| 551b77f5a1 | |||
| 7932583d9d | |||
| 79e3ec2f0d |
3
.gitignore
vendored
@@ -4,4 +4,5 @@ obj/
|
|||||||
riderModule.iml
|
riderModule.iml
|
||||||
/_ReSharper.Caches/
|
/_ReSharper.Caches/
|
||||||
.idea/
|
.idea/
|
||||||
*.user
|
*.user
|
||||||
|
.nuke/temp
|
||||||
@@ -1,19 +1,48 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"$ref": "#/definitions/build",
|
|
||||||
"title": "Build Schema",
|
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"build": {
|
"Host": {
|
||||||
"type": "object",
|
"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": {
|
"properties": {
|
||||||
"Configuration": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
|
|
||||||
"enum": [
|
|
||||||
"Debug",
|
|
||||||
"Release"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Continue": {
|
"Continue": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Indicates to continue a previously failed build attempt"
|
"description": "Indicates to continue a previously failed build attempt"
|
||||||
@@ -23,25 +52,8 @@
|
|||||||
"description": "Shows the help text for this build assembly"
|
"description": "Shows the help text for this build assembly"
|
||||||
},
|
},
|
||||||
"Host": {
|
"Host": {
|
||||||
"type": "string",
|
|
||||||
"description": "Host for execution. Default is 'automatic'",
|
"description": "Host for execution. Default is 'automatic'",
|
||||||
"enum": [
|
"$ref": "#/definitions/Host"
|
||||||
"AppVeyor",
|
|
||||||
"AzurePipelines",
|
|
||||||
"Bamboo",
|
|
||||||
"Bitbucket",
|
|
||||||
"Bitrise",
|
|
||||||
"GitHubActions",
|
|
||||||
"GitLab",
|
|
||||||
"Jenkins",
|
|
||||||
"Rider",
|
|
||||||
"SpaceAutomation",
|
|
||||||
"TeamCity",
|
|
||||||
"Terminal",
|
|
||||||
"TravisCI",
|
|
||||||
"VisualStudio",
|
|
||||||
"VSCode"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"NoLogo": {
|
"NoLogo": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -70,44 +82,41 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "List of targets to be skipped. Empty list skips all dependencies",
|
"description": "List of targets to be skipped. Empty list skips all dependencies",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string",
|
"$ref": "#/definitions/ExecutableTarget"
|
||||||
"enum": [
|
|
||||||
"Clean",
|
|
||||||
"Publish",
|
|
||||||
"PublishLinux",
|
|
||||||
"PublishWin",
|
|
||||||
"Restore"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Target": {
|
"Target": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "List of targets to be invoked. Default is '{default_target}'",
|
"description": "List of targets to be invoked. Default is '{default_target}'",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string",
|
"$ref": "#/definitions/ExecutableTarget"
|
||||||
"enum": [
|
|
||||||
"Clean",
|
|
||||||
"Publish",
|
|
||||||
"PublishLinux",
|
|
||||||
"PublishWin",
|
|
||||||
"Restore"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Verbosity": {
|
"Verbosity": {
|
||||||
"type": "string",
|
|
||||||
"description": "Logging verbosity during build execution. Default is 'Normal'",
|
"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": [
|
"enum": [
|
||||||
"Minimal",
|
"Debug",
|
||||||
"Normal",
|
"Release"
|
||||||
"Quiet",
|
|
||||||
"Verbose"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Version": {
|
"Version": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/NukeBuild"
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Assets/.DS_Store
vendored
Normal file
BIN
Assets/favicon_io.zip
Normal file
BIN
Assets/favicon_io/.DS_Store
vendored
Normal file
6
Assets/favicon_io/about.txt
Normal 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))
|
||||||
1
Assets/favicon_io/site.webmanifest
Normal 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"}
|
||||||
@@ -12,6 +12,7 @@ Global
|
|||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{C0C29CAE-A5C1-43B8-BFF8-BFE718FE04E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{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}.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.ActiveCfg = Debug|Any CPU
|
||||||
{637A753B-3168-4C9C-8098-7A16024E1957}.Debug|Any CPU.Build.0 = 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
|
{637A753B-3168-4C9C-8098-7A16024E1957}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|||||||
BIN
K8sFileBrowser/.DS_Store
vendored
Normal file
@@ -10,7 +10,7 @@
|
|||||||
</Application.DataTemplates>
|
</Application.DataTemplates>
|
||||||
|
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<FluentTheme>
|
<FluentTheme DensityStyle="Compact">
|
||||||
<FluentTheme.Palettes>
|
<FluentTheme.Palettes>
|
||||||
<!-- Palette for Light theme variant -->
|
<!-- Palette for Light theme variant -->
|
||||||
<ColorPaletteResources x:Key="Light" Accent="Green" RegionColor="White" ErrorText="Red" />
|
<ColorPaletteResources x:Key="Light" Accent="Green" RegionColor="White" ErrorText="Red" />
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
Accent="#677696"
|
Accent="#677696"
|
||||||
RegionColor="#282c34"
|
RegionColor="#282c34"
|
||||||
ErrorText="Red"
|
ErrorText="Red"
|
||||||
AltHigh="#282c34"
|
AltHigh="#343a45"
|
||||||
AltMediumLow="#2c313c"
|
AltMediumLow="#2c313c"
|
||||||
ListLow="#21252b"
|
ListLow="#21252b"
|
||||||
ListMedium="#2c313c"
|
ListMedium="#2c313c"
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
ChromeMediumLow="#21252b"
|
ChromeMediumLow="#21252b"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- AltHigh is used for the color of header in the DataGrid -->
|
<!-- AltHigh is used for the color of header in the DataGrid -->
|
||||||
<!-- BaseHigh is used for the text color -->
|
<!-- BaseHigh is used for the text color -->
|
||||||
<!-- ListLow is used for the mouse over in lists and DataGrid -->
|
<!-- ListLow is used for the mouse over in lists and DataGrid -->
|
||||||
|
|||||||
BIN
K8sFileBrowser/Assets/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
K8sFileBrowser/Assets/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
K8sFileBrowser/Assets/android-chrome-512x512_128x128.icns
Normal file
BIN
K8sFileBrowser/Assets/android-chrome-512x512_16x16.icns
Normal file
BIN
K8sFileBrowser/Assets/android-chrome-512x512_256x256.icns
Normal file
BIN
K8sFileBrowser/Assets/android-chrome-512x512_32x32.icns
Normal file
BIN
K8sFileBrowser/Assets/android-chrome-512x512_512x512.icns
Normal file
BIN
K8sFileBrowser/Assets/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
K8sFileBrowser/Assets/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 337 B |
BIN
K8sFileBrowser/Assets/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 708 B |
BIN
K8sFileBrowser/Assets/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
@@ -9,8 +9,8 @@
|
|||||||
<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.9</Version>
|
<Version>0.1.4</Version>
|
||||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
@@ -22,21 +22,21 @@
|
|||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
<PackageReference Include="Avalonia" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.5" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--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 Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.2" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.5" />
|
||||||
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Xaml.Interactions" Version="11.2.0.14" />
|
||||||
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.0.2" />
|
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="11.2.0.14" />
|
||||||
<PackageReference Include="KubernetesClient" Version="11.0.44" />
|
<PackageReference Include="KubernetesClient" Version="16.0.2" />
|
||||||
<PackageReference Include="ReactiveUI.Fody" Version="19.4.1" />
|
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
<PackageReference Include="Serilog" Version="4.2.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
|
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using System;
|
using System;
|
||||||
|
using Avalonia.Logging;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace K8sFileBrowser;
|
namespace K8sFileBrowser;
|
||||||
@@ -18,6 +19,7 @@ class Program
|
|||||||
//.Filter.ByIncludingOnly(Matching.WithProperty("Area", LogArea.Control))
|
//.Filter.ByIncludingOnly(Matching.WithProperty("Area", LogArea.Control))
|
||||||
.MinimumLevel.Information()
|
.MinimumLevel.Information()
|
||||||
.WriteTo.Async(a => a.File("app.log"))
|
.WriteTo.Async(a => a.File("app.log"))
|
||||||
|
//.WriteTo.Console()
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
|
|
||||||
BuildAvaloniaApp()
|
BuildAvaloniaApp()
|
||||||
@@ -42,5 +44,6 @@ class Program
|
|||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
.WithInterFont()
|
.WithInterFont()
|
||||||
.LogToTrace()
|
.LogToTrace()
|
||||||
|
//.LogToTrace(LogEventLevel.Verbose)
|
||||||
.UseReactiveUI();
|
.UseReactiveUI();
|
||||||
}
|
}
|
||||||
@@ -1,33 +1,42 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Concurrency;
|
using System.Reactive.Concurrency;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using K8sFileBrowser.Models;
|
using K8sFileBrowser.Models;
|
||||||
using K8sFileBrowser.Services;
|
using K8sFileBrowser.Services;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ReactiveUI.Fody.Helpers;
|
using ReactiveUI.Fody.Helpers;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace K8sFileBrowser.ViewModels;
|
namespace K8sFileBrowser.ViewModels;
|
||||||
|
|
||||||
public class MainWindowViewModel : ViewModelBase
|
public class MainWindowViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private ObservableAsPropertyHelper<IEnumerable<ClusterContext>> _clusterContexts = null!;
|
|
||||||
public IEnumerable<ClusterContext> ClusterContexts => _clusterContexts.Value;
|
#region Properties
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public string? Version { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public IEnumerable<ClusterContext> ClusterContexts { get; set; } = null!;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public ClusterContext? SelectedClusterContext { get; set; }
|
public ClusterContext? SelectedClusterContext { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public IEnumerable<Namespace> Namespaces { get; set; }
|
public IEnumerable<Namespace> Namespaces { get; set; } = null!;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public Namespace? SelectedNamespace { get; set; }
|
public Namespace? SelectedNamespace { get; set; }
|
||||||
|
|
||||||
private ObservableAsPropertyHelper<IEnumerable<Pod>> _pods = null!;
|
[Reactive]
|
||||||
public IEnumerable<Pod> Pods => _pods.Value;
|
public IEnumerable<Pod> Pods { get; set; } = null!;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public Pod? SelectedPod { get; set; }
|
public Pod? SelectedPod { get; set; }
|
||||||
@@ -38,8 +47,8 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
[Reactive]
|
[Reactive]
|
||||||
public Container? SelectedContainer { get; set; }
|
public Container? SelectedContainer { get; set; }
|
||||||
|
|
||||||
private ObservableAsPropertyHelper<IEnumerable<FileInformation>> _fileInformation = null!;
|
[Reactive]
|
||||||
public IEnumerable<FileInformation> FileInformation => _fileInformation.Value;
|
public IEnumerable<FileInformation> FileInformation { get; set; } = null!;
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public FileInformation? SelectedFile { get; set; }
|
public FileInformation? SelectedFile { get; set; }
|
||||||
@@ -48,24 +57,33 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
public string? SelectedPath { get; set; }
|
public string? SelectedPath { get; set; }
|
||||||
|
|
||||||
[Reactive]
|
[Reactive]
|
||||||
public Message Message { get; set; }
|
public Message Message { get; set; } = null!;
|
||||||
|
|
||||||
|
private string _lastDirectory = ".";
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> DownloadCommand { get; private set; } = null!;
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Commands
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> DownloadLogCommand { get; private set; } = null!;
|
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<Unit, Unit> ParentCommand { get; private set; } = null!;
|
||||||
public ReactiveCommand<Unit, Unit> OpenCommand { 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!;
|
private ReactiveCommand<Namespace, IEnumerable<Pod>> GetPodsForNamespace { get; set; } = null!;
|
||||||
|
|
||||||
|
#endregion Commands
|
||||||
|
|
||||||
public MainWindowViewModel()
|
public MainWindowViewModel()
|
||||||
{
|
{
|
||||||
//TODO: use dependency injection to get the kubernetes service
|
|
||||||
IKubernetesService kubernetesService = new KubernetesService();
|
IKubernetesService kubernetesService = new KubernetesService();
|
||||||
|
|
||||||
|
Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
ConfigureOpenDirectoryCommand();
|
ConfigureOpenDirectoryContextCommand();
|
||||||
ConfigureDownloadFileCommand(kubernetesService);
|
ConfigureDownloadFileContextCommand(kubernetesService);
|
||||||
|
ConfigureRefreshCommand(kubernetesService);
|
||||||
ConfigureDownloadLogCommand(kubernetesService);
|
ConfigureDownloadLogCommand(kubernetesService);
|
||||||
ConfigureParentDirectoryCommand();
|
ConfigureParentDirectoryCommand();
|
||||||
ConfigureGetPodsForNamespaceCommand(kubernetesService);
|
ConfigureGetPodsForNamespaceCommand(kubernetesService);
|
||||||
@@ -81,68 +99,25 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
InitiallyLoadContexts(kubernetesService);
|
InitiallyLoadContexts(kubernetesService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Property Subscriptions
|
||||||
|
|
||||||
private void InitiallyLoadContexts(IKubernetesService kubernetesService)
|
private void InitiallyLoadContexts(IKubernetesService kubernetesService)
|
||||||
{
|
{
|
||||||
// load the cluster contexts when the view model is created
|
// load the cluster contexts when the view model is created
|
||||||
var loadContexts = ReactiveCommand
|
var loadContexts = ReactiveCommand
|
||||||
.Create<Unit, IEnumerable<ClusterContext>>(_ => kubernetesService.GetClusterContexts());
|
.Create<Unit, IEnumerable<ClusterContext>>(_ => kubernetesService.GetClusterContexts());
|
||||||
_clusterContexts = loadContexts.Execute().ToProperty(
|
loadContexts.Execute()
|
||||||
this, x => x.ClusterContexts, scheduler: RxApp.MainThreadScheduler);
|
|
||||||
|
|
||||||
// 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.SelectedPod, c => c.SelectedNamespace)
|
|
||||||
.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, c => c.SelectedNamespace)
|
|
||||||
.Throttle(new TimeSpan(10))
|
|
||||||
.Select(x => x.Item2 == null || x.Item1 == null
|
|
||||||
? new List<Container>()
|
|
||||||
: x.Item1.Containers.Select(c => new Container {Name = c}))
|
|
||||||
.ObserveOn(RxApp.MainThreadScheduler)
|
|
||||||
.Subscribe( x => Containers = x);
|
|
||||||
|
|
||||||
this.WhenAnyValue(x => x.Containers)
|
|
||||||
.Throttle(new TimeSpan(10))
|
.Throttle(new TimeSpan(10))
|
||||||
.ObserveOn(RxApp.MainThreadScheduler)
|
.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
.Subscribe(x => SelectedContainer = x?.FirstOrDefault());
|
.Subscribe(x =>
|
||||||
}
|
{
|
||||||
|
ResetNamespaces();
|
||||||
|
ClusterContexts = x.OrderBy(c => c.Name);
|
||||||
|
|
||||||
private void RegisterReadFiles(IKubernetesService kubernetesService)
|
// select the current cluster context
|
||||||
{
|
SelectedClusterContext = ClusterContexts
|
||||||
// read the file information when the path changes
|
.FirstOrDefault(c => c.Name == kubernetesService.GetCurrentContext());
|
||||||
_fileInformation = this
|
});
|
||||||
.WhenAnyValue(c => c.SelectedPath, c => c.SelectedPod, c => c.SelectedNamespace, c => c.SelectedContainer)
|
|
||||||
.Throttle(new TimeSpan(10))
|
|
||||||
.Select(x => x.Item3 == null || x.Item2 == null || x.Item1 == null || x.Item4 == null
|
|
||||||
? new List<FileInformation>()
|
|
||||||
: GetFileInformation(kubernetesService, x.Item1, x.Item2, x.Item3, x.Item4))
|
|
||||||
.ObserveOn(RxApp.MainThreadScheduler)
|
|
||||||
.ToProperty(this, x => x.FileInformation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterReadPods()
|
|
||||||
{
|
|
||||||
// read the pods when the namespace changes
|
|
||||||
_pods = this
|
|
||||||
.WhenAnyValue(c => c.SelectedNamespace)
|
|
||||||
.Throttle(new TimeSpan(10))
|
|
||||||
.SelectMany(ns => GetPodsForNamespace.Execute(ns!))
|
|
||||||
.ObserveOn(RxApp.MainThreadScheduler)
|
|
||||||
.ToProperty(this, x => x.Pods);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterReadNamespaces(IKubernetesService kubernetesService)
|
private void RegisterReadNamespaces(IKubernetesService kubernetesService)
|
||||||
@@ -153,16 +128,82 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
.Throttle(new TimeSpan(10))
|
.Throttle(new TimeSpan(10))
|
||||||
.SelectMany(context => GetClusterContextAsync(context, kubernetesService))
|
.SelectMany(context => GetClusterContextAsync(context, kubernetesService))
|
||||||
.ObserveOn(RxApp.MainThreadScheduler)
|
.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
.Subscribe(ns => Namespaces = ns);
|
.Subscribe(ns =>
|
||||||
|
{
|
||||||
|
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)
|
private void ConfigureGetPodsForNamespaceCommand(IKubernetesService kubernetesService)
|
||||||
{
|
{
|
||||||
GetPodsForNamespace = ReactiveCommand.CreateFromObservable<Namespace, IEnumerable<Pod>>(ns =>
|
GetPodsForNamespace = ReactiveCommand.CreateFromObservable<Namespace, IEnumerable<Pod>>(ns =>
|
||||||
Observable.StartAsync(_ => PodsAsync(ns, kubernetesService), RxApp.TaskpoolScheduler));
|
Observable.StartAsync(_ => PodsAsync(ns, kubernetesService), RxApp.TaskpoolScheduler));
|
||||||
|
|
||||||
GetPodsForNamespace.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
GetPodsForNamespace.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
|
.Subscribe(ShowErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureParentDirectoryCommand()
|
private void ConfigureParentDirectoryCommand()
|
||||||
@@ -181,7 +222,7 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
}, isNotRoot, RxApp.MainThreadScheduler);
|
}, isNotRoot, RxApp.MainThreadScheduler);
|
||||||
|
|
||||||
ParentCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
ParentCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
|
.Subscribe(ShowErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureDownloadLogCommand(IKubernetesService kubernetesService)
|
private void ConfigureDownloadLogCommand(IKubernetesService kubernetesService)
|
||||||
@@ -195,9 +236,10 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
await Observable.StartAsync(async () =>
|
await Observable.StartAsync(async () =>
|
||||||
{
|
{
|
||||||
var fileName = SelectedPod?.Name + ".log";
|
var fileName = SelectedPod?.Name + ".log";
|
||||||
var saveFileName = await ApplicationHelper.SaveFile(".", fileName);
|
var saveFileName = await ApplicationHelper.SaveFile(_lastDirectory, fileName);
|
||||||
if (saveFileName != null)
|
if (saveFileName != null)
|
||||||
{
|
{
|
||||||
|
SetLastDirectory(saveFileName);
|
||||||
ShowWorkingMessage("Downloading Log...");
|
ShowWorkingMessage("Downloading Log...");
|
||||||
await kubernetesService.DownloadLog(SelectedNamespace, SelectedPod, SelectedContainer, saveFileName);
|
await kubernetesService.DownloadLog(SelectedNamespace, SelectedPod, SelectedContainer, saveFileName);
|
||||||
HideWorkingMessage();
|
HideWorkingMessage();
|
||||||
@@ -206,53 +248,73 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
}, isSelectedPod, RxApp.MainThreadScheduler);
|
}, isSelectedPod, RxApp.MainThreadScheduler);
|
||||||
|
|
||||||
DownloadLogCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
DownloadLogCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
|
.Subscribe(ShowErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureRefreshCommand(IKubernetesService kubernetesService)
|
||||||
|
{
|
||||||
|
var isSelectedContainer = this
|
||||||
|
.WhenAnyValue(x => x.SelectedContainer)
|
||||||
|
.Select(x => x != null);
|
||||||
|
|
||||||
|
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 ConfigureDownloadFileCommand(IKubernetesService kubernetesService)
|
|
||||||
|
|
||||||
|
private void ConfigureDownloadFileContextCommand(IKubernetesService kubernetesService)
|
||||||
{
|
{
|
||||||
var isFile = this
|
|
||||||
.WhenAnyValue(x => x.SelectedFile, x => x.Message.IsVisible)
|
|
||||||
.Select(x => x is { Item1.Type: FileType.File, Item2: false });
|
|
||||||
|
|
||||||
DownloadCommand = ReactiveCommand.CreateFromTask(async () =>
|
DownloadContextCommand = ReactiveCommand.CreateFromTask<FileInformation>(async (file) =>
|
||||||
{
|
{
|
||||||
await Observable.StartAsync(async () =>
|
await Observable.StartAsync(async () =>
|
||||||
{
|
{
|
||||||
var fileName = SelectedFile!.Name.Substring(SelectedFile!.Name.LastIndexOf('/') + 1,
|
var fileName = file.Name.Substring(SelectedFile!.Name.LastIndexOf('/') + 1,
|
||||||
SelectedFile!.Name.Length - SelectedFile!.Name.LastIndexOf('/') - 1);
|
file.Name.Length - file.Name.LastIndexOf('/') - 1);
|
||||||
var saveFileName = await ApplicationHelper.SaveFile(".", fileName);
|
var saveFileName = await ApplicationHelper.SaveFile(_lastDirectory, fileName);
|
||||||
if (saveFileName != null)
|
if (saveFileName != null)
|
||||||
{
|
{
|
||||||
|
SetLastDirectory(saveFileName);
|
||||||
ShowWorkingMessage("Downloading File...");
|
ShowWorkingMessage("Downloading File...");
|
||||||
await kubernetesService.DownloadFile(SelectedNamespace, SelectedPod, SelectedContainer, SelectedFile, saveFileName);
|
await kubernetesService.DownloadFile(SelectedNamespace, SelectedPod, SelectedContainer, file, saveFileName);
|
||||||
HideWorkingMessage();
|
HideWorkingMessage();
|
||||||
}
|
}
|
||||||
}, RxApp.TaskpoolScheduler);
|
}, RxApp.TaskpoolScheduler);
|
||||||
}, isFile, RxApp.MainThreadScheduler);
|
}, outputScheduler: RxApp.MainThreadScheduler);
|
||||||
|
|
||||||
DownloadCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
DownloadContextCommand.ThrownExceptions.ObserveOn(RxApp.MainThreadScheduler)
|
||||||
.Subscribe(ex => ShowErrorMessage(ex.Message).ConfigureAwait(false).GetAwaiter().GetResult());
|
.Subscribe(ShowErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConfigureOpenDirectoryCommand()
|
private void SetLastDirectory(string saveFileName)
|
||||||
{
|
{
|
||||||
var isDirectory = this
|
_lastDirectory = saveFileName.Substring(0, saveFileName.LastIndexOf(Path.DirectorySeparatorChar));
|
||||||
.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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
private static async Task<IEnumerable<Pod>> PodsAsync(Namespace? ns, IKubernetesService kubernetesService)
|
||||||
{
|
{
|
||||||
@@ -277,10 +339,8 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
RxApp.MainThreadScheduler.Schedule(Action);
|
ShowErrorMessage(e);
|
||||||
return new List<Namespace>();
|
return new List<Namespace>();
|
||||||
|
|
||||||
async void Action() => await ShowErrorMessage(e.Message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,35 +368,89 @@ public class MainWindowViewModel : ViewModelBase
|
|||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowWorkingMessage(string message)
|
#endregion Get Data
|
||||||
|
|
||||||
|
#region Reset Data
|
||||||
|
|
||||||
|
private void ResetPath()
|
||||||
{
|
{
|
||||||
Message = new Message
|
FileInformation = new List<FileInformation>();
|
||||||
{
|
SelectedPath = null;
|
||||||
IsVisible = true,
|
SelectedContainer = null;
|
||||||
Text = message,
|
|
||||||
IsError = false
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
Message = new Message
|
||||||
Text = message,
|
{
|
||||||
IsError = true
|
IsVisible = true,
|
||||||
};
|
Text = message,
|
||||||
await Task.Delay(7000);
|
IsError = false
|
||||||
HideWorkingMessage();
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
private void HideWorkingMessage()
|
||||||
{
|
{
|
||||||
Message = new Message
|
RxApp.MainThreadScheduler.Schedule(() => Message = new Message
|
||||||
{
|
{
|
||||||
IsVisible = false,
|
IsVisible = false,
|
||||||
Text = "",
|
Text = "",
|
||||||
IsError = false
|
IsError = false
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion show messages
|
||||||
}
|
}
|
||||||
@@ -15,180 +15,300 @@
|
|||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
|
|
||||||
<Grid>
|
<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">
|
<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 Classes="loading" Data="{StaticResource arrow_rotate_clockwise_regular}" Width="100"
|
||||||
<PathIcon Data="{StaticResource warning_regular}" Width="100" Height="100" IsVisible="{Binding Message.IsError}"></PathIcon>
|
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>
|
<TextBlock TextWrapping="Wrap" Text="{Binding Message.Text}">.</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
<Grid RowDefinitions="Auto, *">
|
<Grid RowDefinitions="Auto, *">
|
||||||
<Border Padding="10 14" Background="#21252b">
|
<Border Padding="10 14" Background="#21252b">
|
||||||
<Grid ColumnDefinitions="Auto,Auto,Auto,*">
|
<Grid ColumnDefinitions="Auto,Auto,Auto,*,Auto">
|
||||||
<Label Grid.Column="0"
|
<Label Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="0 0 10 0">
|
Margin="0 0 10 0">
|
||||||
Cluster:
|
Cluster:
|
||||||
</Label>
|
</Label>
|
||||||
<ComboBox Grid.Column="1"
|
<ComboBox Grid.Column="1"
|
||||||
ItemsSource="{Binding ClusterContexts}"
|
ItemsSource="{Binding ClusterContexts}"
|
||||||
SelectedItem="{Binding SelectedClusterContext}"
|
SelectedItem="{Binding SelectedClusterContext}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
MinWidth="200"
|
MinWidth="200"
|
||||||
Margin="0 0 10 0">
|
Margin="0 0 10 0">
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
<Label Grid.Column="2"
|
<Label Grid.Column="2"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="0 0 10 0">
|
Margin="0 0 10 0">
|
||||||
Namespace:
|
Namespace:
|
||||||
</Label>
|
</Label>
|
||||||
<ComboBox Grid.Column="3"
|
<ComboBox Grid.Column="3"
|
||||||
ItemsSource="{Binding Namespaces}"
|
ItemsSource="{Binding Namespaces}"
|
||||||
SelectedItem="{Binding SelectedNamespace}"
|
SelectedItem="{Binding SelectedNamespace}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
MinWidth="200"
|
MinWidth="200"
|
||||||
Margin="0 0 10 0">
|
Margin="0 0 10 0">
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
<TextBlock Grid.Column="4" HorizontalAlignment="Right" VerticalAlignment="Center"
|
||||||
</Border>
|
Text="{Binding Version}" />
|
||||||
|
</Grid>
|
||||||
<Grid ColumnDefinitions="*, 1, 3*" Grid.Row="1">
|
</Border>
|
||||||
<ListBox
|
|
||||||
ItemsSource="{Binding Pods}"
|
<Grid ColumnDefinitions="*, 1, 3*" Grid.Row="1">
|
||||||
SelectedItem="{Binding SelectedPod}" Background="Transparent">
|
<ListBox
|
||||||
<ListBox.Styles>
|
ItemsSource="{Binding Pods}"
|
||||||
<Style Selector="ListBoxItem">
|
SelectedItem="{Binding SelectedPod}" Background="Transparent">
|
||||||
<Setter Property="Padding" Value="0" />
|
<ListBox.Styles>
|
||||||
</Style>
|
<Style Selector="ListBoxItem">
|
||||||
</ListBox.Styles>
|
<Setter Property="Padding" Value="0" />
|
||||||
<ListBox.ItemTemplate>
|
</Style>
|
||||||
<DataTemplate>
|
</ListBox.Styles>
|
||||||
<Border CornerRadius="0" Padding="0 4 0 4" BorderBrush="SlateGray"
|
<ListBox.ItemTemplate>
|
||||||
BorderThickness="0 0 0 1">
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding}" Padding="4" Margin="4" />
|
<Border CornerRadius="0" Padding="0 4 0 4" BorderBrush="SlateGray"
|
||||||
</Border>
|
BorderThickness="0 0 0 1">
|
||||||
</DataTemplate>
|
<TextBlock Text="{Binding}" Padding="4" Margin="4" />
|
||||||
</ListBox.ItemTemplate>
|
</Border>
|
||||||
</ListBox>
|
</DataTemplate>
|
||||||
<GridSplitter Grid.Column="1" ResizeDirection="Columns" />
|
</ListBox.ItemTemplate>
|
||||||
<Grid Grid.Column="2" RowDefinitions="Auto, *">
|
</ListBox>
|
||||||
<Grid ColumnDefinitions="*, Auto, Auto">
|
<GridSplitter Grid.Column="1" ResizeDirection="Columns" />
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
<Grid Grid.Column="2" RowDefinitions="Auto, *">
|
||||||
<TextBlock Text="Current Directory" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
|
<Grid ColumnDefinitions="*, Auto, Auto">
|
||||||
<TextBlock Text="{Binding SelectedPath}" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
|
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||||
</StackPanel>
|
<TextBlock Text="Current Directory" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
|
||||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
|
<TextBlock Text="{Binding SelectedPath}" VerticalAlignment="Center" Margin="10 0 0 0"></TextBlock>
|
||||||
<Label VerticalAlignment="Center"
|
</StackPanel>
|
||||||
Margin="0 0 10 0">
|
<StackPanel Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
|
||||||
Container:
|
<Label VerticalAlignment="Center"
|
||||||
</Label>
|
Margin="0 0 10 0">
|
||||||
<ComboBox ItemsSource="{Binding Containers}"
|
Container:
|
||||||
SelectedItem="{Binding SelectedContainer}"
|
</Label>
|
||||||
VerticalAlignment="Center"
|
<ComboBox ItemsSource="{Binding Containers}"
|
||||||
MinWidth="200"
|
SelectedItem="{Binding SelectedContainer}"
|
||||||
Margin="0 0 10 0">
|
VerticalAlignment="Center"
|
||||||
</ComboBox>
|
MinWidth="200"
|
||||||
</StackPanel>
|
Margin="0 0 10 0">
|
||||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="10" HorizontalAlignment="Right">
|
</ComboBox>
|
||||||
<Button Command="{Binding DownloadLogCommand}" VerticalAlignment="Center" ToolTip.Tip="Download Container Log" Margin="0 0 48 0 ">
|
</StackPanel>
|
||||||
<PathIcon Data="{StaticResource document_one_page_regular}"></PathIcon>
|
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="10"
|
||||||
</Button>
|
HorizontalAlignment="Right">
|
||||||
<Button Command="{Binding ParentCommand}" VerticalAlignment="Center" ToolTip.Tip="Go To Parent Directory">
|
<Button Command="{Binding DownloadLogCommand}" VerticalAlignment="Center"
|
||||||
<PathIcon Data="{StaticResource arrow_curve_up_left_regular}"></PathIcon>
|
ToolTip.Tip="Download Container Log" Margin="0 0 48 0 ">
|
||||||
</Button>
|
<PathIcon Data="{StaticResource document_one_page_regular}"></PathIcon>
|
||||||
<Button Command="{Binding OpenCommand}" VerticalAlignment="Center" ToolTip.Tip="Browse Directory">
|
</Button>
|
||||||
<PathIcon Data="{StaticResource arrow_right_regular}"></PathIcon>
|
<Button Command="{Binding RefreshCommand}" VerticalAlignment="Center"
|
||||||
</Button>
|
ToolTip.Tip="Refresh Directory">
|
||||||
<Button Command="{Binding DownloadCommand}" VerticalAlignment="Center" ToolTip.Tip="Download File">
|
<PathIcon Data="{StaticResource arrow_sync_circle_regular}"></PathIcon>
|
||||||
<PathIcon Data="{StaticResource arrow_download_regular}"></PathIcon>
|
</Button>
|
||||||
</Button>
|
<Button Command="{Binding ParentCommand}" VerticalAlignment="Center"
|
||||||
</StackPanel>
|
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>
|
</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 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>
|
|
||||||
<DataGridTemplateColumn Header="Date" CanUserSort="False">
|
|
||||||
<DataGridTemplateColumn.CellTemplate>
|
|
||||||
<DataTemplate DataType="models:FileInformation">
|
|
||||||
<Border Background="Transparent">
|
|
||||||
<TextBlock Text="{Binding DateTimeOffsetString}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0 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>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
|
||||||
</Window>
|
</Window>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<!-- This manifest is used on Windows only.
|
<!-- This manifest is used on Windows only.
|
||||||
Don't remove it as it might cause problems with window transparency and embeded controls.
|
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 -->
|
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">
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
<application>
|
<application>
|
||||||
|
|||||||
10
README.md
@@ -3,4 +3,14 @@
|
|||||||
A UI tool for downloading files from a Pod.
|
A UI tool for downloading files from a Pod.
|
||||||
The application is also the first Avalonia UI and C# UI app I have written.
|
The application is also the first Avalonia UI and C# UI app I have written.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Just start the executable and select the cluster, namespace and pod you want to download files from.
|
||||||
|
Then select the files you want to download and click the download button.
|
||||||
|
|
||||||
|
The available clusters are read from the `~/.kube/config` file.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
It only works on linux containers and the container must support `find` and `tar`.
|
||||||
|
|
||||||

|

|
||||||
103
build/Build.cs
@@ -1,42 +1,43 @@
|
|||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
using Nuke.Common;
|
using Nuke.Common;
|
||||||
using Nuke.Common.IO;
|
using Nuke.Common.IO;
|
||||||
using Nuke.Common.ProjectModel;
|
|
||||||
using Nuke.Common.Tooling;
|
using Nuke.Common.Tooling;
|
||||||
using Nuke.Common.Tools.DotNet;
|
using Nuke.Common.Tools.DotNet;
|
||||||
using static Nuke.Common.Tools.DotNet.DotNetTasks;
|
using static Nuke.Common.Tools.DotNet.DotNetTasks;
|
||||||
|
|
||||||
class Build : NukeBuild
|
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.5.0";
|
||||||
|
|
||||||
AbsolutePath SourceDirectory => RootDirectory / "K8sFileBrowser";
|
AbsolutePath SourceDirectory => RootDirectory / "K8sFileBrowser";
|
||||||
AbsolutePath OutputDirectory => RootDirectory / "output";
|
AbsolutePath OutputDirectory => RootDirectory / "output";
|
||||||
AbsolutePath WinOutputDirectory => OutputDirectory / "win";
|
AbsolutePath WinOutputDirectory => OutputDirectory / "win";
|
||||||
AbsolutePath LinuxOutputDirectory => OutputDirectory / "linux";
|
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";
|
AbsolutePath ProjectFile => SourceDirectory / "K8sFileBrowser.csproj";
|
||||||
|
|
||||||
|
readonly string ExcludedExtensions = "pdb";
|
||||||
|
|
||||||
public static int Main () => Execute<Build>(x => x.Publish);
|
public static int Main () => Execute<Build>(x => x.Publish);
|
||||||
|
|
||||||
[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";
|
|
||||||
|
|
||||||
Target Clean => _ => _
|
Target Clean => _ => _
|
||||||
.Before(Restore)
|
|
||||||
.Executes(() =>
|
.Executes(() =>
|
||||||
{
|
{
|
||||||
DotNetClean(s => s
|
OutputDirectory.DeleteDirectory();
|
||||||
.SetOutput(OutputDirectory));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Target Restore => _ => _
|
|
||||||
.Executes(() =>
|
|
||||||
{
|
|
||||||
DotNet($"restore {ProjectFile}");
|
|
||||||
//DotNetTasks.DotNetRestore(new DotNetRestoreSettings());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Target PublishWin => _ => _
|
Target PublishWin => _ => _
|
||||||
.DependsOn(Clean)
|
.DependsOn(Clean)
|
||||||
.Executes(() =>
|
.Executes(() =>
|
||||||
@@ -45,44 +46,78 @@ class Build : NukeBuild
|
|||||||
.SetProject(ProjectFile)
|
.SetProject(ProjectFile)
|
||||||
.SetConfiguration(Configuration)
|
.SetConfiguration(Configuration)
|
||||||
.SetOutput(WinOutputDirectory)
|
.SetOutput(WinOutputDirectory)
|
||||||
.SetSelfContained(true)
|
.EnableSelfContained()
|
||||||
.SetFramework("net7.0")
|
.SetFramework("net8.0")
|
||||||
.SetRuntime("win-x64")
|
.SetRuntime("win-x64")
|
||||||
.SetPublishSingleFile(true)
|
.EnablePublishSingleFile()
|
||||||
.SetPublishReadyToRun(true)
|
.EnablePublishReadyToRun()
|
||||||
.SetAuthors("Andreas Billmann")
|
.SetAuthors("Andreas Billmann")
|
||||||
.SetCopyright("Copyright (c) 2023")
|
.SetCopyright("Copyright (c) 2023")
|
||||||
.SetVersion(Version)
|
.SetVersion(Version)
|
||||||
.SetProcessArgumentConfigurator(_ => _
|
.SetProcessArgumentConfigurator(_ => _
|
||||||
.Add("-p:IncludeNativeLibrariesForSelfExtract=true"))
|
.Add("-p:IncludeNativeLibrariesForSelfExtract=true")));
|
||||||
.EnableNoRestore());
|
|
||||||
|
WinOutputDirectory.ZipTo(
|
||||||
|
WinZip,
|
||||||
|
filter: x => !x.HasExtension(ExcludedExtensions),
|
||||||
|
compressionLevel: CompressionLevel.SmallestSize,
|
||||||
|
fileMode: FileMode.CreateNew);
|
||||||
});
|
});
|
||||||
|
|
||||||
Target PublishLinux => _ => _
|
Target PublishLinux => _ => _
|
||||||
.DependsOn(Clean)
|
.DependsOn(Clean)
|
||||||
.Executes(() =>
|
.Executes(() =>
|
||||||
{
|
{
|
||||||
DotNetPublish(s => s
|
DotNetPublish(s => s
|
||||||
.SetProject(ProjectFile)
|
.SetProject(ProjectFile)
|
||||||
.SetConfiguration(Configuration)
|
.SetConfiguration(Configuration)
|
||||||
.SetOutput(LinuxOutputDirectory)
|
.SetOutput(LinuxOutputDirectory)
|
||||||
.SetSelfContained(true)
|
.EnableSelfContained()
|
||||||
.SetFramework("net7.0")
|
.SetFramework("net8.0")
|
||||||
.SetRuntime("linux-x64")
|
.SetRuntime("linux-x64")
|
||||||
.SetPublishSingleFile(true)
|
.EnablePublishSingleFile()
|
||||||
.SetPublishReadyToRun(true)
|
.EnablePublishReadyToRun()
|
||||||
.SetAuthors("Andreas Billmann")
|
.SetAuthors("Andreas Billmann")
|
||||||
.SetCopyright("Copyright (c) 2023")
|
.SetCopyright("Copyright (c) 2023")
|
||||||
.SetVersion(Version)
|
.SetVersion(Version)
|
||||||
.SetProcessArgumentConfigurator(_ => _
|
.SetProcessArgumentConfigurator(_ => _
|
||||||
.Add("-p:IncludeNativeLibrariesForSelfExtract=true"))
|
.Add("-p:IncludeNativeLibrariesForSelfExtract=true")));
|
||||||
.EnableNoRestore());
|
|
||||||
|
LinuxOutputDirectory.TarGZipTo(
|
||||||
|
LinuxGz,
|
||||||
|
filter: x => !x.HasExtension(ExcludedExtensions),
|
||||||
|
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 => _ => _
|
Target Publish => _ => _
|
||||||
.DependsOn(PublishWin, PublishLinux)
|
.DependsOn(PublishWin, PublishLinux, PublishOsx)
|
||||||
.Executes(() =>
|
.Executes(() =>
|
||||||
{
|
{
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RootNamespace></RootNamespace>
|
<RootNamespace></RootNamespace>
|
||||||
<NoWarn>CS0649;CS0169</NoWarn>
|
<NoWarn>CS0649;CS0169</NoWarn>
|
||||||
<NukeRootDirectory>..</NukeRootDirectory>
|
<NukeRootDirectory>..</NukeRootDirectory>
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Nuke.Common" Version="7.0.2" />
|
<PackageReference Include="Nuke.Common" Version="8.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
<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"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue"><Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue"><Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy></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_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_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@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_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_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_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
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"rollForward": "latestFeature",
|
||||||
|
"allowPrerelease": false
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
screenshot.png
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 150 KiB |