Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4eacc74
chore: add solution file and Core project structure
Kofysh Jun 4, 2026
8c18268
feat(core): add API models, ApiClient async, AuthService, Configurati…
Kofysh Jun 4, 2026
b227930
feat(app): add App.xaml, MainWindow, LoginPage + LoginViewModel
Kofysh Jun 4, 2026
afead14
feat(app): add MainPage, MainViewModel, MachineCard control
Kofysh Jun 4, 2026
af1db5c
feat(app): add ConsolePage (WebView2), SpiceLauncher, helpers and man…
Kofysh Jun 4, 2026
6a03b8a
feat(core): add Models, ConfigurationService, ApiClient async (System…
Kofysh Jun 4, 2026
edae886
chore(assets): add copy-assets script, solution file and app manifest
Kofysh Jun 4, 2026
2335212
fix(scripts): use MyInvocation pour resoudre PSScriptRoot en dot-sour…
Kofysh Jun 4, 2026
4e5accd
fix(scripts): supprimer param() pour eviter conflit d'arguments en do…
Kofysh Jun 4, 2026
54abcaa
fix(scripts): compatibilite PowerShell 5 - Join-Path chaine + [IO.Pat…
Kofysh Jun 4, 2026
55be33d
fix(csproj): migrer net8 -> net10, maj versions packages pour SDK .NE…
Kofysh Jun 4, 2026
bf9d6c8
fix(build): global.json + nuget.config + maj packages vers dernieres …
Kofysh Jun 4, 2026
a6ba30d
fix(models): MachineData -> record class (support 'with'), PowerResul…
Kofysh Jun 4, 2026
7e1c340
fix(build): supprimer LoginResult.cs doublon (definissait PowerResult…
Kofysh Jun 4, 2026
2cf0508
fix(xaml): supprimer TextTransform (WinUI3) + doublon Content sur But…
Kofysh Jun 4, 2026
b32fb71
fix(build): Lock/Serial dans MachineData, FindParent helper, RootFram…
Kofysh Jun 4, 2026
f96c79d
fix(build): supprimer prop RootFrame en doublon avec le champ généré …
Kofysh Jun 4, 2026
0493b92
fix(build): supprimer UIHelper.cs (doublon de VisualTreeHelperExtensi…
Kofysh Jun 4, 2026
263a862
fix(warnings): migrer [ObservableProperty] vers partial property (MVV…
Kofysh Jun 4, 2026
3b19e9a
fix(startup): mode unpackaged + WindowsAppSdkBootstrap pour corriger …
Kofysh Jun 4, 2026
f9bafed
fix(startup): exclure Package.appxmanifest du build unpackaged (confl…
Kofysh Jun 4, 2026
26d5239
Add compiled build outputs and assets
Kofysh Jun 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Build WinUI 3

on:
push:
branches: [ feature/winui3-migration ]
pull_request:
branches: [ main ]

jobs:
build:
runs-on: windows-latest

steps:
- uses: actions/checkout@v4

- name: Setup .NET 8
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Copy assets from Resources/
shell: pwsh
run: .\scripts\copy-assets.ps1

- name: Restore NuGet packages
run: dotnet restore src/ProxmoxDesktop.sln

- name: Build (Release x64)
run: dotnet build src/ProxmoxDesktop.sln
--configuration Release
--no-restore
-p:Platform=x64
25 changes: 25 additions & 0 deletions ProxmoxDesktop.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxmoxDesktop.App", "src\ProxmoxDesktop.App\ProxmoxDesktop.App.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxmoxDesktop.Core", "src\ProxmoxDesktop.Core\ProxmoxDesktop.Core.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.ActiveCfg = Debug|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|x64.Build.0 = Debug|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.ActiveCfg = Release|x64
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|x64
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|x64.ActiveCfg = Debug|x64
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|x64.Build.0 = Debug|x64
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|x64.ActiveCfg = Release|x64
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|x64.Build.0 = Release|x64
EndGlobalSection
EndGlobal
71 changes: 71 additions & 0 deletions scripts/copy-assets.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# copy-assets.ps1
# Copie les assets depuis Resources/ vers src/ProxmoxDesktop.App/Assets/
#
# Compatible PowerShell 5.1 et PowerShell 7+
# Usage (toutes les formes fonctionnent) :
# .\scripts\copy-assets.ps1
# & '.\scripts\copy-assets.ps1'
# . '.\scripts\copy-assets.ps1'

$ErrorActionPreference = "Stop"

# Retrouver le dossier du script (robuste en appel direct ET dot-sourcing)
$_scriptPath = if ($MyInvocation.MyCommand.Path) {
$MyInvocation.MyCommand.Path
} elseif ($PSCommandPath) {
$PSCommandPath
} else {
[IO.Path]::Combine((Get-Location).Path, 'scripts', 'copy-assets.ps1')
}

$_repoRoot = [IO.Path]::GetFullPath([IO.Path]::Combine((Split-Path $_scriptPath), '..'))
$SourceRoot = [IO.Path]::Combine($_repoRoot, 'Resources')
$DestRoot = [IO.Path]::Combine($_repoRoot, 'src', 'ProxmoxDesktop.App', 'Assets')

Write-Host "Repo : $_repoRoot"
Write-Host "Source : $SourceRoot"
Write-Host "Dest : $DestRoot"
Write-Host ""

if (-not (Test-Path $SourceRoot)) {
Write-Error "Dossier Resources introuvable : $SourceRoot`nVerifie que tu lances le script depuis la racine du repo."
return
}

New-Item -ItemType Directory -Force -Path $DestRoot | Out-Null

$copies = @(
@{ Src = [IO.Path]::Combine('Icons', 'default.png'); Dst = 'proxmox.png' }
@{ Src = [IO.Path]::Combine('Icons', 'default-icon.ico'); Dst = 'app.ico' }
@{ Src = 'vm_logo.png'; Dst = 'vm.png' }
@{ Src = 'lxc_logo.png'; Dst = 'lxc.png' }
)

$ok = 0
$warn = 0

foreach ($item in $copies) {
$src = [IO.Path]::Combine($SourceRoot, $item.Src)
$dst = [IO.Path]::Combine($DestRoot, $item.Dst)

if (-not (Test-Path $src)) {
Write-Warning "Source introuvable : $src"
$warn++
continue
}

Copy-Item -Path $src -Destination $dst -Force
Write-Host "[OK] $($item.Src) -> Assets/$($item.Dst)" -ForegroundColor Cyan
$ok++
}

Write-Host ""
if ($warn -gt 0) {
Write-Warning "$warn fichier(s) manquant(s)."
}
if ($ok -gt 0) {
Write-Host "$ok asset(s) copies avec succes dans : $DestRoot" -ForegroundColor Green
Write-Host "Lance maintenant : dotnet build src/ProxmoxDesktop.sln"
} else {
Write-Error "Aucun asset copie. Verifie que Resources/ est bien present a la racine du repo."
}
33 changes: 33 additions & 0 deletions scripts/copy-assets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# copy-assets.sh
# Equivalent bash de copy-assets.ps1 (pour WSL ou CI Linux).
# Usage depuis la racine du repo :
# bash scripts/copy-assets.sh

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)"
SOURCE_ROOT="$SCRIPT_DIR/../Resources"
DEST_ROOT="$SCRIPT_DIR/../src/ProxmoxDesktop.App/Assets"

mkdir -p "$DEST_ROOT"

copy_asset() {
local src="$SOURCE_ROOT/$1"
local dst="$DEST_ROOT/$2"
if [ ! -f "$src" ]; then
echo "[WARN] Source introuvable : $src"
return
fi
cp "$src" "$dst"
echo "[OK] $1 -> Assets/$2"
}

copy_asset "Icons/default.png" "proxmox.png"
copy_asset "Icons/default-icon.ico" "app.ico"
copy_asset "vm_logo.png" "vm.png"
copy_asset "lxc_logo.png" "lxc.png"

echo ""
echo "Assets copiés avec succès dans : $DEST_ROOT"
echo "Tu peux maintenant compiler avec : dotnet build src/ProxmoxDesktop.sln"
13 changes: 13 additions & 0 deletions src/ProxmoxDesktop.App/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="ProxmoxDesktop.App.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
17 changes: 17 additions & 0 deletions src/ProxmoxDesktop.App/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.UI.Xaml;
using ProxmoxDesktop.App.Views;

namespace ProxmoxDesktop.App;

public partial class App : Application
{
public static MainWindow? MainWindow { get; private set; }

public App() => InitializeComponent();

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MainWindow = new MainWindow();
MainWindow.Activate();
}
}
2 changes: 2 additions & 0 deletions src/ProxmoxDesktop.App/Assets/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Place proxmox.png, vm.png, lxc.png in this folder.
# Copy from the original WinForms project Resources/ folder.
28 changes: 28 additions & 0 deletions src/ProxmoxDesktop.App/Assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Assets — ProxmoxDesktop.App

Ce dossier contient les images utilisées par l'interface WinUI 3.
Les fichiers binaires (PNG, ICO) ne sont **pas** commités dans Git
pour éviter de dupliquer les ressources déjà présentes dans `/Resources/`.

## Copier les assets

Exécute **une seule fois** depuis la racine du repo :

**Windows (PowerShell) :**
```powershell
.\scripts\copy-assets.ps1
```

**Linux / WSL (Bash) :**
```bash
bash scripts/copy-assets.sh
```

## Fichiers attendus

| Fichier | Source originale | Rôle |
|---|---|---|
| `proxmox.png` | `Resources/Icons/default.png` | Logo Proxmox (header, splash) |
| `vm.png` | `Resources/vm_logo.png` | Icône des VM QEMU sur les tiles |
| `lxc.png` | `Resources/lxc_logo.png` | Icône des containers LXC sur les tiles |
| `app.ico` | `Resources/Icons/default-icon.ico` | Icône de l'application (barre des tâches) |
114 changes: 114 additions & 0 deletions src/ProxmoxDesktop.App/Controls/MachineCard.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="ProxmoxDesktop.App.Controls.MachineCard"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:models="using:ProxmoxDesktop.Core.Api.Models">

<Grid Width="175" Height="195" Padding="0"
CornerRadius="8"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1">

<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!-- Badge de statut -->
<!-- Mode=OneTime : StatusBrush est une propriété calculée sans INotifyPropertyChanged.
La card est recréée à chaque refresh différentiel, ce qui force la réévaluation. -->
<Border HorizontalAlignment="Right" VerticalAlignment="Top"
Margin="0,8,8,0" CornerRadius="4" Padding="6,2"
Background="{x:Bind StatusBrush, Mode=OneTime}">
<TextBlock Text="{x:Bind Machine.Status, Mode=OneWay}"
FontSize="10" Foreground="White"
CharacterSpacing="75" FontWeight="SemiBold"/>
</Border>

<!-- Node name -->
<Border HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="8,8,0,0" CornerRadius="4" Padding="6,2"
Background="{ThemeResource SystemFillColorNeutralBackground}">
<TextBlock Text="{x:Bind Machine.NodeName, Mode=OneWay}"
FontSize="10"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
</Border>

<!-- Icône VM/LXC centrée -->
<!-- Mode=OneTime : MachineIcon (qemu/lxc) ne change pas après création -->
<Image Grid.Row="0"
Source="{x:Bind MachineIcon, Mode=OneTime}"
Width="72" Height="72"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,16,0,0"/>

<!-- Barres CPU / RAM -->
<StackPanel Grid.Row="0" VerticalAlignment="Bottom"
Padding="10,0,10,4" Spacing="4">
<Grid ColumnDefinitions="Auto,*">
<TextBlock Grid.Column="0" Text="CPU" FontSize="10" Width="28"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<ProgressBar Grid.Column="1" Value="{x:Bind Machine.CpuPercent, Mode=OneWay}"
Maximum="100" Height="4"/>
</Grid>
<Grid ColumnDefinitions="Auto,*">
<TextBlock Grid.Column="0" Text="RAM" FontSize="10" Width="28"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
<ProgressBar Grid.Column="1" Value="{x:Bind Machine.MemPercent, Mode=OneWay}"
Maximum="100" Height="4"/>
</Grid>
</StackPanel>

<!-- Nom + VMID -->
<StackPanel Grid.Row="1" Padding="10,6,10,10" Spacing="2">
<TextBlock Text="{x:Bind Machine.Name, Mode=OneWay}"
FontWeight="SemiBold" FontSize="13"
TextTrimming="CharacterEllipsis"/>
<TextBlock Text="{x:Bind Machine.Vmid, Mode=OneWay}"
FontSize="11"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
</StackPanel>

<!-- Menu contextuel (clic droit ou bouton …) -->
<Grid.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem Text="NoVNC"
Command="{x:Bind OpenNoVncCommand}"
IsEnabled="{x:Bind Machine.IsRunning, Mode=OneWay}">
<MenuFlyoutItem.Icon><FontIcon Glyph="&#xE8A7;"/></MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Text="xTermJS"
Command="{x:Bind OpenXtermCommand}"
IsEnabled="{x:Bind CanOpenXterm, Mode=OneWay}">
<MenuFlyoutItem.Icon><FontIcon Glyph="&#xE756;"/></MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem Text="SPICE"
Command="{x:Bind OpenSpiceCommand}"
IsEnabled="{x:Bind Machine.IsRunning, Mode=OneWay}">
<MenuFlyoutItem.Icon><FontIcon Glyph="&#xE7F4;"/></MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutSeparator/>
<MenuFlyoutSubItem Text="Alimentation">
<MenuFlyoutItem Text="Démarrer" Command="{x:Bind StartCommand}"
IsEnabled="{x:Bind CanStart, Mode=OneWay}"/>
<MenuFlyoutItem Text="Arrêter" Command="{x:Bind ShutdownCommand}"
IsEnabled="{x:Bind Machine.IsRunning, Mode=OneWay}"/>
<MenuFlyoutItem Text="Redémarrer" Command="{x:Bind RebootCommand}"
IsEnabled="{x:Bind Machine.IsRunning, Mode=OneWay}"/>
<MenuFlyoutItem Text="Suspendre" Command="{x:Bind SuspendCommand}"
IsEnabled="{x:Bind CanSuspend, Mode=OneWay}"/>
<MenuFlyoutItem Text="Reprendre" Command="{x:Bind ResumeCommand}"
IsEnabled="{x:Bind CanResume, Mode=OneWay}"/>
<MenuFlyoutItem Text="Hiberner" Command="{x:Bind HibernateCommand}"
IsEnabled="{x:Bind CanSuspend, Mode=OneWay}"/>
<MenuFlyoutItem Text="Stop forcé" Command="{x:Bind StopCommand}"
IsEnabled="{x:Bind Machine.IsRunning, Mode=OneWay}"/>
<MenuFlyoutItem Text="Reset" Command="{x:Bind ResetCommand}"
IsEnabled="{x:Bind CanReset, Mode=OneWay}"/>
</MenuFlyoutSubItem>
</MenuFlyout>
</Grid.ContextFlyout>
</Grid>
</UserControl>
Loading
Loading