Commit Graph

12 Commits

Author SHA1 Message Date
67f422539d v0.12.0 — Report tool auto-deploy from PROSERVE ZIP
Each PROSERVE ZIP can ship a _report/ subfolder alongside _migrations/.
After install + DB migration, the launcher copies _report/ to the local
XAMPP htdocs (default C:\xampp\htdocs\ProserveReport\) so the Reports
tab in the sidebar always serves the matching version.

Service (PSLauncher.Core/ReportTool)
- IReportToolDeployer + ReportToolDeployer.
- Atomic deploy: copy to {target}.new/ → rename current to .old/ →
  rename .new → final → cleanup .old. Apache never sees a half-state.
- Skip silencieux si _report/ absent du ZIP (PROSERVE release qui ne
  touche pas au Report).
- DeployStatus enum (SkippedNoSourceFolder, XamppNotFound, Failed,
  Deployed) renvoyé pour gestion UI claire.

Config (LocalConfig)
- ReportToolConfig (HtdocsRoot, FolderName, AutoDeploy). Defaults
  matchent l'install standard ASTERION (C:\xampp\htdocs\ProserveReport).

Install pipeline (MainViewModel)
- Étape 6 après extraction + migrations. Progress reporté via le footer
  Library : « 📂 Déploiement Report : 47/120 — assets/main.js ».
  XAMPP introuvable → dialog avec lien vers Settings → Avancés.

Settings UI (SettingsDialog → Avancés)
- Nouveau bloc « OUTIL REPORT (XAMPP htdocs) » : 2 champs path + checkbox
  AutoDeploy + bouton « 📂 Re-déployer maintenant » qui rejoue le deploy
  sur la dernière version installée. Utile après changement de chemin
  htdocs ou si l'auto-deploy avait foiré (XAMPP éteint).

Versions bumped to 0.12.0 (App + Updater + installer .iss).

Côté release : tu ajoutes _report/ dans le source de PROSERVE, tu zippes,
tu uploades. Les clients récupèrent ZIP + migrations + Report en une
seule install.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 09:05:40 +02:00
288cad585a Right sidebar nav: Library / Reports / Documentation tabs (WebView2)
The body of the launcher is now a 2-column layout:
- Left : swappable content area
- Right (200px) : sidebar with 3 nav buttons + active-state highlighting

Three pages, all under the same window chrome / footer:

1. **Library** (default) — the existing main view (featured version,
   other versions list, floating "Vérifier les MAJ" button, copyright).
2. **Reports** — embedded WebView2 navigated to a configurable URL.
   Default http://localhost/ProserveReport/ which matches the local
   stats tool installed on each customer machine alongside XAMPP.
3. **Documentation** — WebView2 with a configurable URL, falls back
   to a placeholder explaining where to set it if empty.

Implementation
- LocalConfig gains ReportUrl + DocumentationUrl (string).
- MainViewModel gains LauncherPage enum + CurrentPage state with
  Navigate{Library,Report,Documentation}Command. ReportUri /
  DocumentationUri parse the strings to Uri for WebView2.Source.
- Theme.xaml: NavButton style (transparent, left-aligned, hover
  darken, active state highlighted via Tag bool + accent left-border).
- InverseBoolToVisibilityConverter added (true → Collapsed) for the
  documentation placeholder fallback.
- Microsoft.Web.WebView2 NuGet (1.0.2792.45). Runtime is pre-installed
  on Win11 and auto-pushed via Windows Update on Win10. If absent,
  WebView2 surfaces an error which the user sees inline.
- Settings → Avancés → Serveur extended with the two URL fields.
- Strings.cs: NavLibrary / NavReport / NavDocumentation,
  SettingsReportUrl / SettingsDocsUrl, DocsPlaceholder, WebViewLoadError.
  Sidebar localized in 5 languages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 08:52:51 +02:00
f62b212fc1 Settings: About goes above Advanced (Advanced is the last block)
Reorders the bottom of the Settings dialog so the "À propos" section
(version + copyright) sits between Langue and the collapsed Advanced
expander. The Expander becomes the very last item, since power-user
plumbing is naturally what the eye should reach last.

DB default name was already set to "proserveapi" in the previous commit
(LocalConfig.cs line 64) — re-confirmed.

Final order:
  1. License de mise à jour       [expanded]
  2. Langue                        [expanded]
  3. À propos                      [expanded]
  4. ▸ Paramètres avancés          [collapsed]

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 08:41:43 +02:00
f86895553a Settings: collapse advanced sections + dedicated About + default DB name
- DB default name: "proserve" → "proserveapi" (matches the ASTERION install
  script that provisions XAMPP on client machines).
- Settings dialog reorganized:
   1. License de mise à jour     [expanded] ← business-critical
   2. Langue                     [expanded] ← user preference
   3. ▸ PARAMÈTRES AVANCÉS       [collapsed by default]
        contains Server, Installation, Cache, Database, Logs
   4. À PROPOS                   [expanded] ← version + copyright
- The Expander hides plumbing the casual user shouldn't touch (server URL,
  install root, MySQL config, cache directory) but keeps it one click away
  for power users / support diagnostics.
- About card kept always-visible because version info is what support asks
  for first when troubleshooting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 08:36:57 +02:00
750bb8cfc9 Settings: Database section with connection params, test, and replay button
New « BASE DE DONNÉES (XAMPP / MySQL) » section in Paramètres covering:

- Host / Port / User / Password / Database — defaults match a fresh XAMPP
  install (localhost:3306, root, empty password, "proserve"). Password is
  DPAPI-encrypted in config.json (same scheme as the license key).
- « Tester » button — opens a fresh MySqlConnection and runs SELECT 1.
  Shows ✓ OK or the connection error inline.
- « Appliquer automatiquement les migrations à l'install » checkbox — opt-in
  for the post-install migration step. Default true.
- « 🔁 Rejouer les migrations » button — manually re-runs ApplyMigrationsAsync
  on the latest installed version. Useful when the post-install run failed
  (XAMPP was off) or after a dev added a new SQL file. Live status « 3/5 :
  0042_add_index.sql » + final « ✓ N applied, M skipped » or « ✗ failure ».
- Hint paragraph below explaining the _migrations/ convention.

SettingsViewModel
- Pulls IDatabaseMigrationService and IInstallationRegistry via DI.
- Save() now also persists the DB block, encrypting the password before write.
- TestDbAsync temporarily swaps the in-memory config so the service sees the
  values being typed (without persisting until Save).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 08:25:32 +02:00
b4f205cbe5 i18n: full pass + culture-aware dates/sizes + Software Update License wording
- Strings.cs : ~80 new keys covering status messages, progress detail
  (DL/extraction/verify), license summary, license details dialog, onboarding
  statuses, settings field labels, restart/cancel/quit confirmations, toasts,
  resume choice, copyright. Strings.FormatSize and Strings.FormatDate /
  FormatLongDate switch units (o/Ko vs B/KB) and pattern (dd/MM/yyyy vs M/d/yyyy
  vs 2026年) by active language.
- License terminology renamed across UI: "License" → "License de mise à jour"
  / "Software Update License" to clarify it gates UPDATES, not Proserve itself.
  Expired/revoked dialogs now spell out "you can still download versions
  released before this date and launch any installed version".
- "🔒 License insuffisante" → "🔒 License de mise à jour requise pour cette
  version" / "Valid update license needed for this version" so users understand
  it's a per-version eligibility check, not a global block.
- All hardcoded FR strings in views (SettingsDialog labels, LicenseDetails
  fields, Onboarding statuses, dialog titles, copyright, window chrome
  tooltips, "Sortie le", etc.) replaced with x:Static loc bindings.
- All FormatSize duplicates (5 places) and date format strings (8 places)
  delegate to Strings helpers — single source of truth for localization.
- Settings dialog: License section moved to the top before Language. It's
  the most important info and conditions what the user can download.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 19:14:57 +02:00
01a11d5616 i18n: 5 languages (FR/EN/ZH/TH/AR), auto-detect from Windows + Settings picker
Localization infrastructure
---------------------------
PSLauncher.Core/Localization/Strings.cs is a static class exposing each
UI string as a static property. T(fr,en,zh,th,ar) helper switches by the
current language code. ~50 keys cover the visible top-level strings:
top bar, body, status badges, action buttons, "..." menu items, license
badge texts, Settings section headers, Onboarding dialog, Update dialog.

Bindings via x:Static in XAML:
  xmlns:loc="clr-namespace:PSLauncher.Core.Localization;assembly=PSLauncher.Core"
  Content="{x:Static loc:Strings.ActionLaunch}"

Auto-detection
--------------
LocalConfig gains a Language field defaulting to "auto". Strings.Init()
called at App.xaml.cs OnStartup before any UI:
- "auto" (or unknown code) → reads CultureInfo.CurrentUICulture
  .TwoLetterISOLanguageName, picks the matching supported language,
  falls back to English.
- explicit code → forced.
The chosen culture is then propagated to CurrentCulture / CurrentUICulture
so date/number formats follow.

Settings picker
---------------
SettingsDialog gets a top section "LANGUE" with a ComboBox bound to
SettingsViewModel.AvailableLanguages (Auto / FR / EN / ZH / TH / AR).
On Save, if the language code changed, prompt the user to confirm
restart, spawn `cmd /c timeout 1 & start PSLauncher.exe` and Shutdown
the current process — the new instance picks up the language at
bootstrap.

RTL for Arabic
--------------
Strings.IsRightToLeft is true when lang=="ar". App.xaml.cs sets
window.FlowDirection = RightToLeft on the MainWindow — WPF mirrors the
layout (icons on right, text aligned right).

Translations
------------
Done as best-effort by the assistant. The product wordmark "PROSERVE"
stays untranslated (brand). Logs and debug-level messages remain in
French in code — only user-visible UI is localized. Operator can
refine translations by editing Strings.cs and rebuilding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:02:50 +02:00
8ebde15535 Copyright: readable pill with proper "© 2026 ASTERION VR — All rights reserved"
The previous copyright was a faded TextBlock at Opacity 0.7 with the
secondary grey color, sitting directly on top of the variable-
luminance background image. Hard to read on the bright spots of the
ASTERION VR engraving.

Wrap it in a Border with #A0000000 background (~63% opacity black)
and CornerRadius=10 — same pill style as the license badge — so the
text reads cleanly regardless of what's behind. Foreground is now
plain white instead of the secondary grey.

Text changed from the terse "© ASTERION VR" to the proper convention:
- UI: "© 2026 ASTERION VR — Tous droits réservés" (matches the
  French-language UI in MainWindow + Settings)
- Assembly metadata (Properties → Détails on the .exe): English form
  "© 2026 ASTERION VR — All rights reserved"

Same change applied to PSLauncher.Updater.csproj.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 11:48:25 +02:00
dfad967eae branding: ASTERION VR favicon + copyright everywhere
Icon
----
src/favicon64.jpg converted to favicon.ico (single-resolution 64x64)
via PowerShell + System.Drawing.Icon.FromHandle. The .ico is now an
EmbeddedResource of PSLauncher.App and referenced as:
- <ApplicationIcon> on PSLauncher.App.csproj → .exe icon in
  Explorer / taskbar / Alt-Tab
- Window.Icon on every WPF window: MainWindow, SettingsDialog,
  OnboardingDialog, LicenseDetailsDialog, UpdateAvailableDialog,
  ReleaseNotesViewerDialog, LauncherUpdateDialog
- <ApplicationIcon> on PSLauncher.Updater.csproj → updater also
  carries the brand icon
- SetupIconFile in installer/PSLauncher.iss → the Inno Setup .exe
  installer shows the icon too

Copyright
---------
- <Company>, <Product>, <Copyright> assembly attributes set in
  both csprojs → properties dialog on the .exe shows "© ASTERION VR".
- MainWindow body has a discreet floating "© ASTERION VR" text in the
  bottom-right, mirroring the "Vérifier les MAJ" button on the left.
  Opacity 0.7 + secondary color so it doesn't compete with the cards.
- SettingsDialog "Logs & Application" section gains a
  "© ASTERION VR — Tous droits réservés" line under the version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 11:44:28 +02:00
b10a3fbabf UI overhaul: minimal top bar, license-first settings, footer-pinned check
Top bar (3-column layout)
-------------------------
- Col 1: PROSERVE Launcher wordmark.
- Col 2: license badge centered, the badge IS the click target now (a
  Border with an InputBindings MouseBinding LeftClick to OpenLicense).
  No more separate "🔑 Activer / changer" button cluttering the right.
- Col 3: ⚙ Paramètres + window chrome (min/max/close).
- "📁 Dossier" button removed from the top bar — install root is still
  reachable from Settings.

Footer (always visible)
-----------------------
- Row 1: "🔄 Vérifier les MAJ" pinned bottom-left, always shown. The
  optional "Annuler" button stays bottom-right while a download runs.
- Row 2: status text + progress bar, only shown when busy or after a
  status message — the previous "footer entirely hidden when idle"
  hid the check button too.

License flow split in two
-------------------------
Click on the license badge:
- License is active (valid / expired / revoked) → LicenseDetailsDialog
  opens. Header pill in matching status color (green/amber/red), shows
  owner, validity, issued date, machine ID with copy-to-clipboard. Two
  buttons: "🗑 Désactiver la license" (with confirmation) and Close.
- No license OR after deactivation → falls through to the existing
  OnboardingDialog for re-keying.

Settings rework
---------------
LICENSE section is now first in SettingsDialog with the same
green/amber/red colored chrome as the top bar — at a glance the user
sees the same status everywhere. Machine ID copy moved into this card.

Sign-manifest no longer needs exec()
------------------------------------
The "🔁 Sync" button in admin/versions.php previously shelled out to
`php tools/sign-manifest.php` via exec(). OVH mutualisé often disables
exec(), causing silent no-ops and the symptom the user just hit: the
ZIP changed (new size 469,657,770 vs manifest's stale 469,831,428) and
the launcher rejected it as size mismatch.

Refactor:
- New PSLauncher\Tools\SignManifest class with ->run() that does the
  hashing, latest-bump and Ed25519 signing in-process.
- tools/sign-manifest.php is now a 6-line wrapper for the class.
- admin/versions.php's 'sync' action calls the class directly via
  require_once + new — works on any host, no exec dependency.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 09:24:01 +02:00
b33b35b198 Fix Settings crash: Run.Text needs Mode=OneWay on read-only sources
Stack trace from %LocalAppData%/PSLauncher/logs/app-*.log pinpointed the
exact line:

  System.InvalidOperationException: Une liaison TwoWay ou OneWayToSource
  ne peut pas fonctionner sur la propriété en lecture seule
  'LauncherVersion' de type SettingsViewModel.

WPF's <Run Text="{Binding ...}"> defaults to TwoWay binding (unlike
TextBlock.Text which defaults to OneWay). Bound to a `{ get; }`-only
property like LauncherVersion, the binding system tries to install a
back-channel writer at AttachToContext time, fails, and crashes the
whole window during ShowDialog().

Fix: explicit Mode=OneWay on the affected <Run>. The other read-only
view-model properties used in this dialog (MachineId, LogsDirectory,
CacheDirectory, LicenseInfo) are bound through TextBlock.Text and are
unaffected.

For posterity: serilog file sink + AppDomain.UnhandledException hook
captured the failure with the full stack — exactly the diagnostic flow
v0.5 was meant to enable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:46:05 +02:00
eeff3c007b v0.5: settings dialog, persistent Serilog logs, Windows toasts
Settings (⚙ button in top bar)
------------------------------
SettingsDialog opens via OpenSettings command in MainViewModel. Sections:
- Serveur: server URL field + "Tester" button that GETs /api/health
  and reports status inline.
- Installation: installRoot path with Browse button
  (Microsoft.Win32.OpenFolderDialog, .NET 8 native).
- License: shows status / owner / exp / machine ID (read-only,
  copy-to-clipboard button), "Désactiver" wipes the cached license.
- Cache: shows download cache path + current size, opens or empties it.
- Logs & Application: launcher version + logs path with "Open" button.

Apply persists to LocalConfig via IConfigStore. After save, MainViewModel
RebuildList()s so changes to ServerBaseUrl or InstallRoot take effect
without restart.

Persistent Serilog logs
-----------------------
Logs now live in %LocalAppData%/PSLauncher/logs/app-YYYYMMDD.log, rolling
daily, 10 days kept. Output template includes source context and stack
traces. Generic Host wired up via .UseSerilog() so all
ILogger<T>-injected types share the sink. Unhandled AppDomain and
Dispatcher exceptions are routed to Serilog before propagation.

Windows toasts
--------------
IToastService + ToastService backed by Microsoft.Toolkit.Uwp.Notifications
(ToastContentBuilder.Show()). Required bumping the App TFM from
net8.0-windows to net8.0-windows10.0.17763.0 (with explicit
WindowsSdkPackageVersion=10.0.17763.41 to satisfy CommunityToolkit.Mvvm
8.3.2's MVVMTKCFG0003 check). Triggered on:
- successful install completion: "Proserve v{X} est prête à être lancée"
- install/download error: short error excerpt

Misc
----
- InverseBoolConverter for "disable button while busy" patterns.
- Added Markdig.Wpf import to ReleaseNotesViewerDialog (was implicit
  before, now required explicitly).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 11:35:22 +02:00