Fix Subsystems tab scroll: match Overview tab layout pattern
Details
The Subsystems tab used Border > ScrollViewer which broke scrolling.
The Overview tab uses a bare ScrollViewer directly in Grid.Row="2"
which works correctly. Matched that pattern:
- Removed Border wrapper around ScrollViewer
- ScrollViewer directly in Grid.Row="2" with IsVisible binding
- Padding="24,0,24,32" matching Overview tab exactly
Fix Unknown subsystem entries and scroll cutoff at bottom
Details
Two issues:
1. "Unknown" group with 5 entries: Plugin SDK calls via TrackedSdkProxy
triggered GetOrCreateState() before DashboardPlugin.CreateViewModelCore
registered the plugin subsystems. The fallback created entries with
DisplayName="Unknown", Category="Unknown".
Fix: GetOrCreateState now infers display name and category from the
subsystem ID pattern. "plugin.privstack.notes" → DisplayName="Notes",
Category="Plugin". Non-plugin IDs get Category="Other" with the raw
ID as name. Register() now uses AddOrUpdate so explicit registration
from DashboardPlugin overwrites auto-created entries with the
authoritative PluginMetadata.Name.
2. Bottom scroll cutoff: Increased ScrollViewer bottom padding from 80
to 120 to clear the macOS dock + app status bar.
Add Auto-Check for Updates toggle in Settings > About
Details
The AutoCheckForUpdates setting existed in AppSettings and was wired in
the ViewModel but had no UI toggle — users couldn't disable it. Added a
ToggleSwitch in the About section (same card pattern as Notifications).
Track plugin SDK activity, fix status dots, guard reminders on setting
Details
Three issues with Subsystems tab accuracy:
1. Status dots: Green only showed for active tasks (task count > 0), so
subsystems with tracked memory but no running task (Crypto/Vault,
Auto-Update, Reminders) showed gray. Now green if tasks > 0 OR
native bytes > 0 OR managed alloc bytes > 0.
2. Plugin activity invisible: Plugins make all data calls through
Host.Sdk.SendAsync, but the shared SdkHost had no subsystem tracking.
Added TrackedSdkProxy that wraps IPrivStackSdk per-plugin — each
PluginHost now gets a scoped proxy tagged with "plugin.<id>". SDK
calls (SendAsync, CountAsync, SearchAsync) enter a subsystem scope,
so navigating to a plugin and loading data shows tracked memory.
3. Reminders allocating with notifications off: The scheduler started
its timer and initial poll unconditionally — PollAsync checked
NotificationsEnabled but already allocated before returning early.
Now guards in Start() itself: if notifications disabled, don't
create the timer or fire the initial poll at all.
Group Subsystems tab by category with section headers
Details
The flat list of ~30 subsystem rows was unmanageable and lacked visual
structure. Now grouped by category (Core, AI, Services, UI, Runtime,
Plugin) with each group showing a bold header, item count + active
summary, per-group column headers, and compact item rows.
- New SubsystemGroupViewModel holds category name, summary, and items
- RefreshSubsystemMetrics builds grouped collections instead of flat list
- XAML uses nested ItemsControl: outer for groups, inner for items
- Dropped the redundant Category column from each row (header shows it)
- Tighter row padding (6,8) and smaller font sizes for compact layout
- Inactive dots at 40% opacity for visual hierarchy
- Bottom padding (24,24,24,80) already handles the lower bar overlap
Get notified about new releases