Commit Graph
1535 Commits
Author SHA1 Message Date
JMR-devandCopilot 27c2a9dc4e Drop unused Microsoft.UI.Xaml.Markup using (Phase 5b step 6 cleanup)
XamlReader-based template generation was removed when sensor tree moved to XAML, so the Markup namespace is no longer referenced.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:37:48 -05:00
JMR-devandCopilot 35f730c89a Host PlotView in MainWindow.xaml (Phase 5b step 5)
PlotView now has a parameterless ctor + AttachViewModel(vm) so it can be instantiated by the XAML loader. The context flyout is built lazily in AttachViewModel since it captures live ViewModel state. Class is now public sealed (XAML codegen requirement). MainWindow's BuildPlotPane is gone; the plot pane (toolbar + <controls:PlotView x:Name=PlotControl/>) lives in XAML and the ctor just calls PlotControl.AttachViewModel(ViewModel).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:36:20 -05:00
JMR-devandCopilot fd55a89e22 Convert sensor pane scaffold and TreeView to MainWindow.xaml (Phase 5b step 4)
Declare the sensor pane (SensorPane), header host (SensorHeaderHost), and TreeView (SensorTree, with its ContentPresenter DataTemplate and SelectionChanged handler) in XAML. The measurer-managed header grid and the per-row CreateSensorRow content remain imperative since they involve dynamic column-width pushing and per-item context flyouts/double-tap handlers; this is the hybrid fallback called out in the Phase 5b plan.

Drop _sensorTree/_sensorPane fields; replace BuildSensorPane with a small PopulateSensorHeader and delete the old XamlReader-loaded DataTemplate.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:31:24 -05:00
JMR-devandCopilot c6ef3edeff Convert MenuBar to MainWindow.xaml (Phase 5b step 3)
Declare File/View/Options/Help menus and their toggle items in XAML with x:Bind (TwoWay) to ViewModel properties. Radio/indexed submenus (Temperature Unit, Plot Location, Theme, Stroke Thickness, File Rotation, Update Interval, Logging Interval, Sensor Values Time Window) are declared as named empty MenuFlyoutSubItems and populated by PopulateRadioSubMenu in code-behind so dynamic check-state and Tag-based selection are preserved.

Click handlers for non-toggle items (save report, reset, expand/collapse, web server dialogs, about, exit) live on the code-behind. Delete BuildMenuBar, CreateToggleItem, CreateToggleSettingItem, BuildRadioSubMenu, BuildIndexedSubMenu. CreateMenuItem is retained for the still-imperative sensor row context menu.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:28:34 -05:00
JMR-devandCopilot fa1b16a8f3 Move status text and loading overlay to MainWindow.xaml (Phase 5b step 2)
Express the status TextBlock and full loading overlay (ProgressRing + label) declaratively with x:Bind to ViewModel.StatusText and ViewModel.HardwareLoadingVisibility. Delete the imperative StatusHost population and BuildLoadingOverlay helper.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:25:55 -05:00
JMR-devandCopilot 0db7de801a Introduce MainWindow.xaml skeleton (Phase 5b step 1)
Make MainWindow partial and add a XAML skeleton with named hosts (MenuHost, ContentGrid, StatusHost, OverlayHost). Replace BuildRoot/AssignContent/ResolveControls with InitializeComponent plus imperative population of the named hosts; existing menu/sensor/plot/overlay builders are unchanged so later sub-steps can replace each region declaratively.

Bind OverlayHost.Visibility to HardwareLoadingVisibility so the empty host does not intercept hit-testing once loading completes. Builders that previously assigned via the brittle Children[] casting now use out params.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:24:30 -05:00
JMR-devandCopilot c9690227d6 Extract SensorColumnMeasurer from MainWindow
Move the text-measurement cache, shared column-width state, 5-second settle timer, and persisted device-column width into a dedicated SensorColumnMeasurer service. MainWindow keeps the traced UpdateSensorColumnWidths wrapper and subscribes to a SettleTriggered event so tracing semantics are preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:16:42 -05:00
JMR-devandCopilot 0cfb9ba3a4 Extract SecondaryWindowCoordinator for plot/gadget lifecycle
Move the PlotWindow + SensorGadgetWindow create/show/sync/close lifecycle out of MainWindow into Services/SecondaryWindowCoordinator. The coordinator owns the _plotWindow and _gadgetWindow fields and exposes UpdatePlotWindowVisibility / UpdateGadgetVisibility / SyncGadgetSensors / ApplyTheme / RedrawPlot / CloseAll.

MainWindow's matching methods become one-line delegators; the gadget's HideShowMainWindowRequested event is wired back via a callback passed into the coordinator's constructor.

MainWindow shrinks from 1362 to 1300 lines; no behaviour change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 13:04:51 -05:00
JMR-devandCopilot 69012a0711 Extract WindowChromeManager + WindowPlacementService
Move Win32 show/hide/minimize/restore tray-chrome logic (the four user32 P/Invokes, the SW_* constants, and the _isMainWindowHidden flag) into Services/WindowChromeManager, and the DPI-aware bounds save/restore + Maximize logic into Services/WindowPlacementService. MainWindow's MainWindow_Closed now delegates to _placementService.Save(); HideShowMainWindow / MinimizeOrHideMainWindow / HideMainWindowToTray delegate to _chromeManager.

Also removes stale PlotBounds/PlotAxisLayout/PlotSeriesSample records that were left behind from the PlotView extraction (dead code; the records now live as private nested types in PlotView).

MainWindow shrinks from 1445 to 1362 lines; no behaviour change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 12:08:24 -05:00
JMR-devandCopilot 888c2cd852 Extract PlotView control from MainWindow
Move ~460 lines of imperative Canvas plot rendering (draw helpers, value/time axes, zoom state, context flyout, wheel handler, color theming, and the PlotBounds/PlotAxisLayout/PlotSeriesSample records) out of MainWindow into a new Controls/PlotView : Grid that owns its own Canvas. PlotWindow now hosts a PlotView instead of a raw Canvas; the shared rendering path collapses to PlotView.Redraw().

MainWindow shrinks from 2014 to 1445 lines; the inline plot pane and the windowed plot now share a single code path. Public API on PlotView: Redraw(), Clear(), ResetZoom(), ApplyTheme(AppThemeMode).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 11:51:46 -05:00
JMR-devandClaude Opus 4.8 ad16c9f3a4 Extract DialogService from MainWindow
Moves the seven ContentDialog flows (rename, pen color, sensor parameters,
web-server settings, web-server authentication, save report, about) plus the
save-report file picker out of MainWindow into a DialogService. The service
reads the live XamlRoot through a provider and writes results back through the
view model; MainWindow's menu/context-menu handlers now delegate to it. The
parameter-editor row builder, the IPv4-address helper, and the
ParameterEditorRow record (all used only by these dialogs) moved with them, and
four now-unused usings were dropped.

First code-only step of the XAML migration; pure relocation, behavior
unchanged. Verified by clean build, 199 tests, and an app smoke-run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:26:35 -05:00
JMR-devandClaude Opus 4.8 6523b570c2 Split TrayIconService into interop, renderer, and orchestration
The 660-line tray service mixed three concerns. Split into:
- TrayIconInterop: all P/Invoke declarations, interop structs, and the
  subclass delegate (consumers use 'using static'), so the Win32 surface is
  isolated and reviewable.
- SensorIconRenderer: the GDI drawing of the 16x16 per-sensor value icon.
- TrayIconService: slimmed to tray orchestration (icon lifecycle, context
  menus, callback routing) at ~340 lines.

Also dedupes the per-sensor settings-key helper onto
SensorSelectionService.GetSensorSettingName. Pure relocation; behavior is
unchanged. Verified by clean build, 199 tests, and an app smoke-run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:14:11 -05:00
JMR-devandClaude Opus 4.8 268f15a19e Extract TreeRebuildCoalescer from HardwareMonitorService
Moves the hardware-change debounce/coalescing worker (the dirty/queued flags
and re-queue logic) into a dedicated class with an injectable delay, so the
concurrency behavior can be unit-tested deterministically instead of living as
an untestable fire-and-forget block in the service. Behavior is unchanged.

Adds 3 tests (single rebuild after delay, burst coalesced to one, no rebuild
when closed) driven by a controllable delay gate.

199 tests pass (was 196).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 11:06:52 -05:00
JMR-devandClaude Opus 4.8 6cd0694cd7 Extract SensorSelectionService from MainWindowViewModel
Moves tray/gadget sensor selection (the per-sensor 'tray'/'gadget' settings,
their key convention, and the GadgetSensorsChanged/TraySensorsChanged events)
into a focused, testable collaborator. The view model keeps thin delegating
methods and forwards the events, so its public surface (used by MainWindow) is
unchanged. Behavior is unchanged.

Adds 3 tests (persistence round-trip, event raising, tray filtering).

196 tests pass (was 193).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:47:40 -05:00
JMR-devandClaude Opus 4.8 4e5e0961d8 Extract PlotTrackingService from MainWindowViewModel
Moves the plot series collection, color palette, retention constants, and
the ~80-line TrackPlotPoints reconciliation (history + retained synthetic
points + current value, de-duplicated by timestamp and pruned to the
retention window) out of the view model into a focused, unit-testable
collaborator. The view model keeps a thin PlotSeries pass-through and
delegates Track/Reset/RefreshSeriesColor. Behavior is unchanged.

Adds 8 tests covering selection add/remove, history+current merge, timestamp
de-duplication, Fahrenheit conversion, reset, and pen-color application.

193 tests pass (was 185).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:42:50 -05:00
JMR-devandClaude Opus 4.8 15737ad639 Harden remote web server security
All changes are localized to RemoteWebServer plus two small helpers; the
Phase 0 characterization tests confirm routing, JSON/Prometheus shape, and
credential pass/fail semantics are otherwise unchanged.

- Password hashing: new PasswordHasher uses PBKDF2-HMAC-SHA256 with a
  per-credential random salt (self-describing pbkdf2$iters$salt$hash).
  Verify() still accepts the legacy unsalted SHA-256 hex hash and a
  successful legacy auth transparently upgrades the stored hash, persisted
  by the view model on save/shutdown. Property renamed PasswordSHA256 ->
  PasswordHash.
- Constant-time comparison: CredentialComparer.FixedTimeEquals for the user
  name and password hash; both are evaluated fully (no && short-circuit).
- No information disclosure: POST failures return a generic message instead
  of ex.ToString(); detail is logged server-side only.
- Bind intent respected: ResolveListenerIp no longer mutates ListenerIp or
  silently falls back to all-interfaces for a specific configured address
  (auto/'?'/wildcards still bind all). A bad address now fails Start().
- CORS: removed the Access-Control-Allow-Origin '*' wildcard; common
  response headers centralized in WriteCommonHeaders.
- Prometheus: label values are escaped (EscapePrometheusLabel).

185 tests pass (was 167).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 10:35:13 -05:00
JMR-devandClaude Opus 4.8 463e80709f Add characterization tests; consolidate SensorFormatter switches
Establishes a safety net before refactoring, and lands the first
behavior-preserving cleanup.

Tests (no production behavior change):
- SensorFormatter: full per-type coverage of GetFormatString, FormatValue,
  and GetPlotUnit across every SensorType.
- RemoteWebServer: extract testable seams (ResolveRoute, VerifyCredentials,
  internal pure helpers) and pin routing (incl. the no-hijack rule), query
  and Prometheus parsing, JSON/metric shape, credential semantics, and the
  legacy SHA-256 vector.
- HardwareMonitorService: pin the enable-flag -> settings-key mapping.
- Logger: add a TimeProvider/base-dir test seam; deterministic rotation tests.
- Add [InternalsVisibleTo] for the test project.

Cleanup:
- Collapse SensorFormatter's three parallel SensorType switches into one
  GetFormat source of truth; dedupe CelsiusToFahrenheit. Verified identical
  by the new characterization tests.

167 tests pass (was 55).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 19:58:44 -05:00
JMR-dev 54a88e1f31 plot window refactor 2026-06-01 18:45:00 -05:00
JMR-dev 667cb4117f update .gitignore 2026-06-01 16:24:09 -05:00
JMR-devandClaude Opus 4.8 c8378e9ab7 Reuse a single TextBlock for sensor-column text measurement
MeasureText runs for every sensor's Value/Min/Max on each update tick, and the
frequently-changing value strings miss the width cache, so it created and threw
away a WinUI TextBlock (with a native peer) on nearly every call. Reuse one
cached instance to avoid that per-tick allocation churn.

Not a leak fix — the GC reclaimed those elements fine; this just removes
needless allocation and CPU work from the update loop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 16:22:34 -05:00
JMR-devandClaude Opus 4.8 93784cc630 Fix tiny window on high-DPI displays and tray restore un-maximizing
AppWindow.Resize/Move take physical pixels and the app is PerMonitorV2-aware,
but RestoreWindowBounds passed the logical default/minimum sizes unscaled, so on
a high-DPI display (e.g. a 200% laptop panel) the window came out at half size.
That showed up when restoring from the tray, since RestoreMainWindow's SW_RESTORE
un-maximizes to that size. Scale the default/minimum sizes by the window DPI via
GetDpiForWindow.

Also stop RestoreMainWindow from un-maximizing: it called SW_RESTORE
unconditionally, collapsing a window that was hidden to the tray while maximized.
Only SW_RESTORE when the window is minimized; otherwise SW_SHOW preserves state.

Verified on a 200% display: the restored window is 1520x1360 (= 760x680 logical)
and stays maximized across tray hide/show.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 16:16:49 -05:00
JMR-devandClaude Opus 4.8 1bde5d531d Fix unbounded memory growth during monitoring
While the app was running, working set grew ~20 MB/min (reaching tens of GB
over a day). dotnet-gcdump traced it to COM-callable wrappers accumulating from
the per-tick binding interop: SensorTreeItemViewModel.RefreshValues raised
PropertyChanged for Value/Min/Max/ToolTip on every sensor every update tick, and
ViewModelBase allocated a new PropertyChangedEventArgs per raise. WinUI's binding
engine is native, so each raised event marshals its args across the boundary and
retains a wrapper.

- ViewModelBase: reuse one cached PropertyChangedEventArgs per property name.
- SensorTreeItemViewModel.RefreshValues: raise PropertyChanged only when the
  formatted text actually changed.

Also close a leaked D3DKMT adapter handle: D3DDisplayDevice.GetDeviceInfoByIdentifier
opened the adapter but skipped CloseAdapter on every early-return failure path,
and it runs on each GPU's Update() tick. Close it in a finally block.

Verified with dotnet-gcdump over an 18-minute soak: managed heap and live object
count stay flat (~50 MB) instead of climbing 47 -> 470 MB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 16:16:40 -05:00
JMR-dev 041e21f9a6 added support for self contained executible 2026-05-30 23:18:32 -05:00
JMR-dev f9edc1dc64 Fixes applied (14 of 15 findings — see note on R5)
Concurrency crashes
  - H1 HardwareMonitorService.RebuildTree now builds the tree under _updateLock, so it can't enumerate a hardware's _active HashSet while the update loop mutates it.
  - A1 AppSettings now guards every dictionary read/write (and snapshots in Save) with a lock — safe under concurrent access from the parallel discovery threads.
  - R2 Plumbed that same lock (HardwareMonitorService.SensorReadLock) into RemoteWebServer and wrapped the Prometheus sensor.Values enumeration with it.
  - L1 Computer — refactored Add into AddCore, which performs the cancellation/enabled re-check and the _groups insertion atomically under _lock. A deferred task can
  no longer add (and leak) a group after Close() drained the list; if it loses the race it closes the group instead.
  - M1 UpdateTimer_Tick now bails before/after the await when _isShuttingDown is set in MainWindow_Closed, so an in-flight tick won't touch the disposed
  view-model/Computer.

  Broken behavior
  - T1 Tray callback now decodes NOTIFYICON_VERSION_4 correctly (message = LOWORD(lParam), icon id = HIWORD(lParam)) — right-click menu and double-click work again.
  - M2 A transient update exception no longer calls _timer.Stop(); the loop keeps running.
  - H2 Newly discovered (deferred) storage devices get the current ForceDriveWakeup setting applied in HardwareChanged.
  - V2 Sensor items carry a parent reference; toggling IsVisible recomputes the parent group's visibility, so no empty group headers. (Strengthened the existing test
  that had skipped this assertion.)
  - H3 Tree-rebuild coalescing now uses a dirty flag with a re-check, so a change arriving during a rebuild isn't lost.
  - R4 Web routing matches endpoints exactly on the query-stripped path (Url.AbsolutePath), so static assets like metrics.html aren't hijacked.
  - L8 IntelCpu.Update skips the bus/core-clock math while TimeStampCounterFrequency is still 0 (deferred-TSC window), so clocks keep their prior value instead of
  reporting 0 MHz.
  - V1 Existing plot series keep their assigned color; only an explicit user pen color updates them (no per-tick color shifting).
  - M3 Runtime errors write to a dedicated runtime.log (once), instead of overwriting the shared startup.log.
  - T2 CreateSensorIcon returns IntPtr.Zero on DIB failure instead of the shared main-icon handle (which callers DestroyIcon).

  I also set _isOpen = false in HardwareMonitorService.Dispose so the rebuild guard actually holds during shutdown (the latent after-close-rebuild issue adjacent to
  H3
2026-05-30 22:56:25 -05:00
JMR-dev 5f88f71e61 added unit tests 2026-05-30 22:07:19 -05:00
JMR-dev c54b5dc4f4 MVP port complete 2026-05-30 20:17:36 -05:00
JMR-dev a1cffce9fd MVP port complete 2026-05-30 19:47:04 -05:00
JMR-dev f8b9949187 performance optimizations - TSC estimation moved off blocking path 2026-05-30 18:55:12 -05:00
JMR-dev c50757868f WIP - optimizing start times 2026-05-30 18:37:39 -05:00
JMR-dev 2c176e5dd7 WIP - optimizing start times 2026-05-30 17:45:37 -05:00
JMR-dev b744f70b0b WIP - optimizing start times 2026-05-30 15:11:32 -05:00
JMR-dev 45bf81ebfa WIP - have working UI for base functions 2026-05-30 14:01:22 -05:00
tj81andTobias Jüttner 95e97cf96b Fix authentication failure after LHM restart caused by double-encoding of stored web-server password. (#2390)
Allow closing of AuthForm via OK without always resetting the existing password.

Co-authored-by: Tobias Jüttner <tjuettner@nepatec.de>
2026-05-29 12:14:40 +02:00
Blacktempel 70df79eb34 Fix nightly link #2388 (#2389) 2026-05-24 16:41:26 +02:00
tj81andTobias Jüttner 10c4f41376 Fix remote web-server crash when sensors contain a "NaN" value. (#2384)
Co-authored-by: Tobias Jüttner <tjuettner@nepatec.de>
2026-05-21 13:11:53 +02:00
Blacktempel 469aa97c77 Fix nuget publish for forks. (#2386) 2026-05-20 15:52:14 +02:00
Blacktempel 2145344e4e Update DiskInfoToolkit. (#2385) 2026-05-20 15:51:44 +02:00
tj81andTobias Jüttner 084aad3e90 Fix web-server resource names when using a different assembly name (e.g. when debugging the Windows forms UI locally). (#2382)
Co-authored-by: Tobias Jüttner <tjuettner@nepatec.de>
2026-05-20 13:49:55 +02:00
PhyxionNL abfc4f5705 Update README to remove WinGet installation section
Removed WinGet installation instructions from README.
2026-05-15 10:31:26 +02:00
Blacktempel e1f284cbb6 Prepare for Avalonia app - rename LHM UI project (#2360)
* Prepare for Avalonia app - rename LHM UI project.

* Rename

* Fix icons not being displayed.

* Rename workflow project
2026-05-15 10:29:57 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 91b01784ca Bump System.IO.Ports from 10.0.7 to 10.0.8 (#2373)
---
updated-dependencies:
- dependency-name: System.IO.Ports
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-13 18:15:55 +02:00
dependabot[bot]anddependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> f2d72f5b5c Bump the all-dependencies group with 4 updates (#2371)
Bumps System.Management from 10.0.7 to 10.0.8
Bumps System.Resources.Extensions from 10.0.7 to 10.0.8
Bumps System.Text.Json from 10.0.7 to 10.0.8
Bumps System.Threading.AccessControl from 10.0.7 to 10.0.8

---
updated-dependencies:
- dependency-name: System.Management
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-dependencies
- dependency-name: System.Resources.Extensions
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-dependencies
- dependency-name: System.Resources.Extensions
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-dependencies
- dependency-name: System.Text.Json
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-dependencies
- dependency-name: System.Threading.AccessControl
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-13 15:54:11 +02:00
Garrett Holland 54b6360ce9 fix: Improve mouse wheel handling for high-resolution devices (#2346) 2026-05-07 13:55:46 +02:00
Blacktempel 17cc90efed Update DiskInfoToolkit. (#2358) 2026-05-03 13:17:41 +02:00
mirko93s 3fb768295a Add support for Asrock B550M Pro4 (#2356) 2026-05-03 10:39:06 +02:00
A1ive a029461c5f Add support for Intel ArrowLake-U (#2357) 2026-05-03 10:30:22 +02:00
PhyxionNL de31b7bf5d Fix PTL voltage (#2351)
* Fix PTL voltage

* Formatting
2026-04-26 19:44:38 +02:00
PhyxionNL 4f58c459ca Add support for Intel Panther Lake microarchitecture (#2332)
* Add support for Intel Panther Lake microarchitecture

* Reorder RaptorLake in CPU microarchitecture list

* Handle unknown microarchitecture case in IntelCpu

* Refactor Intel CPU microarchitecture detection
2026-04-26 19:37:28 +02:00
PhyxionNL 4c50826345 Try to group dependencies
Added new dependency update configuration for Aga.Controls.
2026-04-26 19:37:21 +02:00
PhyxionNL 79b3caf4de Upgrade System.Resources.Extensions to version 10.0.7
Updated System.Resources.Extensions package version from 10.0.6 to 10.0.7.
2026-04-26 19:31:13 +02:00