Repository navigation
CmdPal: Native Adaptive Cards charts and redesigned Performance Monitor cards - #51125
Clint Rutkas (crutkas) wants to merge 29 commits into
Conversation
Adds Command Palette support for the Adaptive Cards Chart.Line element as a custom WinUI element (XAML shapes, theme-aware palette, monotone smoothing, gradient fill, latest-value marker, Task Manager style corner labels), so extensions can send standard chart JSON instead of SVG images. - IncrementalRendering: custom elements can opt in to in-place patching via IncrementalPatchableElements + IIncrementalAdaptiveElementControl, so live charts update (and scroll-animate) without replacing the card. - Container/ColumnSet/Column now honor roundedCorners and showBorder through a decorator around the built-in renderers. - Performance Monitor CPU card: 60-second history chart, speed, base speed, processes, threads, handles, up time, logical processors, and CPU name. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… elements Command Palette now renders more of the current Adaptive Cards schema natively, so extension cards can show rich, theme-aware visuals and still stay standard Adaptive Cards JSON: - Chart.Gauge, Chart.Donut, Chart.Pie, Chart.VerticalBar, Chart.HorizontalBar, and Chart.HorizontalBar.Stacked, plus ProgressBar and Badge. Every element registers through one registry (AdaptiveVisualElements), parses leniently with warnings, and patches in place through the incremental updater. - The host config now uses Fluent design tokens (type ramp, spacing, semantic and container colors) for light, dark, and high contrast, and follows the system accent color. Cards re-render when the theme changes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…and battery cards Each card now leads with its key numbers and draws a 60-second native Chart.Line history, then adds the details that matter for that metric: - Memory: in use and available, plus a composition bar (in use, modified, standby, free) like Task Manager's. - Disk: read and write rates on one auto-scaled axis, plus a capacity bar for each volume on the disk that turns warning or attention as it fills up. - Network: send and receive throughput in the user's unit, plus link speed. The old chart plotted bytes against link speed, so it was usually flat. - GPU: a utilization history alongside the existing details. - Battery: a charge bar colored by level, plus charge or discharge rate, health, and full charge capacity from the aggregate battery report. The DevHome-era SVG chart images are removed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ier sampling - Overview: the list starts with a card that shows every metric at a glance, one tile per metric with its value and the last minute as a sparkline. The tiles show the metric pages' own data, so values match the detail cards, and the detail pages are commands on the card. - GPU: the card adds engine utilization (3D, Copy, Video decode, Video encode) and dedicated and shared GPU memory, as in Task Manager. Short GPU names drop driver details in parentheses, which also shortens the dock label. - Colors: each metric has its own color, and flows use one pair on every card: teal for data coming in and marigold for data going out. - Sampling: pages that show the same metric share its stats, so each stats object is sampled at most once per interval and charts keep one sample per second. A page now samples as soon as it opens, so cards don't start with placeholder values. - Battery: the card hides the time remaining when there isn't one. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Donut: the track ring lined up half a ring inside the slices, because an ellipse strokes inside its bounds while arcs stroke on the radius. - Gauge: segments reach both ends of the arc, and the title aligns with the other charts' titles. - Vertical bars: the zero label no longer floats below the category labels; the minimum is labeled only when it isn't zero. - Add a README for the native visuals: how elements work, theming, and how to add one. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- The extension template's Adaptive Cards skill now covers Chart.Line, Chart.Gauge, Chart.Donut, Chart.Pie, the bar charts, ProgressBar, Badge, and rounded, bordered tiles: properties, colors, live updates, and fallbacks for hosts that don't support them. - The Samples extension has a "Charts and visuals" page that shows every element, with a line chart, gauge, and progress bar that update each second. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The overview can now be pinned to the dock. The band is a single Overview button: its metrics start sampling only when the overview opens, so pinning it costs nothing while the dock is idle. Histories live in the shared stats, so metrics that other pinned bands sample show their last minute right away. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The host config cache held one config, so light and dark card hosts on screen at the same time replaced each other's config, and the next Loaded or theme change re-rendered a card that hadn't changed. Keep the latest few configs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The CPU card ends with a bar for each logical processor, like Task Manager's logical processor view. All processors are read in one batch, and only while a CPU card is open: the dock band and the overview don't request them. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The network card shows the adapter's connection type (Wi-Fi, Ethernet, or Cellular) and its IPv4 and IPv6 addresses, preferring public addresses over private and link-local ones. The all-adapters view describes the connection with the default gateway. Adapter details are cached for 15 seconds, so the card doesn't enumerate adapters every second. The Wi-Fi network name isn't shown because reading it needs location access. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The disk card shows what kind of disk it is, such as SSD (NVMe), and its average response time, as Task Manager does. The disk type comes from a storage property query that needs no access rights, so it works without elevation, and it's read once per disk. Also remove the chart history overload that only the old SVG charts used. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…mory The memory card adds the hardware details from Task Manager's memory page: speed, slots used, form factor, and hardware reserved memory. Speed, slots, and form factor come from the firmware's SMBIOS memory device records, and reserved memory is installed memory that Windows can't use. They don't change while Windows runs, so they're read once. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The CPU card now lists the five processes using the most CPU, as a share of all processors like Task Manager, averaged over the last three seconds so the list stays steady. Processes are read with one NtQuerySystemInformation snapshot per sample, only while the card is open, and the snapshot buffer is released when it closes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adds the Icon element from the current Adaptive Cards schema (name, size, style, color, horizontalAlignment) and the Badge icon and iconPosition properties. Icon names come from the Fluent System Icons catalog that Adaptive Cards uses; Command Palette draws them with Segoe Fluent Icons, which it already uses, through a map of 130 catalog names to the glyphs that draw the same symbols, with filled variants where Segoe has them. Performance Monitor uses icons in the overview tile headers (CPU, memory, GPU, disk, network type, battery level, up time) and in the network, disk, and battery badges. The Samples gallery and the extension-author docs cover the new element. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The GPU card's engine tiles (3D, Copy, Video decode, Video encode) now show a sparkline of the last minute, like Task Manager's engine graphs, instead of a bar of the current value. The engine values were already read every sample, so keeping their history adds no counter reads. Engine and overview sparklines share one scale rule: the top rounds up to the next 10%. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…path CPUStats still carried Dev Home's top-processes code (one performance counter per windowed process, a kill-process helper, and DataType.CpuWithTopProcesses), which nothing enabled. The CPU card's top processes now come from ProcessCpuSampler, so the old path, its timing scaffolding, and the commented-out template bindings are removed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rewords comments and names that check-spelling would flag (grid lines, the monotone cubic reference, SpeedMegaTransfers, sample week labels) and four sentences that matched the forbidden article pattern. Terms that cards show or Windows APIs use are added to expect.txt: dimm, sodimm, hdd, nvme, sparkline, rsmb (the SMBIOS firmware table), and wdk (Windows.Wdk). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- Incremental rendering: a registered element without requires always renders itself, so its fallback is never drawn. The fingerprint now ignores that fallback instead of counting its TextBlocks as unmapped text, which made every text change rebuild cards whose charts have TextBlock fallbacks (the battery card and the Samples gallery). Fallbacks of elements with requires still count. - CPU card: per-processor bars wait for a second sample instead of showing 0%, and samples older than three seconds are discarded, so reopening the card doesn't show an average over the time it was closed. - Process sampler: the snapshot buffer is pinned, because the snapshot holds absolute pointers into it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A horizontal bar chart sized its label column to the longest label, so a long process name could squeeze the bars on the CPU card's top processes. Labels are now at most 40% of the chart's width, trimmed with an ellipsis, with the full label in a tooltip when it's trimmed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The Performance Monitor list titled the disk with the raw counter instance, such as "Disk (0 C:): 3%", while the disk card says "Disk 0 (C:)". The list now uses the card's name: "Disk 0 (C:): 3%". The format string changed meaning, so it has a new resource key. Found while checking the cards in the packaged app. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Release builds compile Command Palette with native AOT. There, CsWinRT finds the projected type of an object it receives by name, which needs the type's metadata. Several values the cards read arrive as plain objects or base types, and without the metadata they came back as bare IInspectable objects: - The incremental updater couldn't read element tags or recognize plain text runs, so every update rebuilt the whole card instead of patching it. The methods that read tags, text blocks, images, and runs now keep that metadata with DynamicDependency. - Text styles and container borders resolved only because other preserved types happen to pull in Style and Border. Without them the line chart legend threw InvalidCastException. The chart text styles and the container decorator now declare those dependencies. - High contrast colors were read as colors boxed in the resources, which can't be unboxed under native AOT, so high contrast cards fell back to fixed colors. They're now read with UISettings.UIElementColor: the same system colors the SystemColor*Color resources use. Checked with a native AOT build of the card harness: every card renders in both themes and updates in place, as in the JIT build.
… something Plugged in and fully charged, the battery is idle, but its report still gives small readings that come and go, such as a 1.1 W discharge. The card showed them as "Discharge rate" next to "Not discharging", and the row appearing and disappearing rebuilt the card every few seconds. The card now shows a charge rate only while charging and a discharge rate only on battery power.
The chart renderers and the Performance Monitor cards used properties that the Adaptive Cards schema doesn't define, so the cards weren't portable and failed strict schema validation: fill, curve, style, minHeight, and valueFormat on Chart.Line; valueFormat on Chart.VerticalBar; yMin, yMax, showBarValues, and valueFormat on Chart.HorizontalBar; and color on Chart.Gauge. Line history was padded with null samples, which the schema's numeric y doesn't allow, and two progress bars used a chart color. The renderers now read only the properties on each element's page of the element reference, with its defaults: - Titles show only with showTitle, legends show by default, and gauges draw their needle unless showNeedle is false. - Chart.HorizontalBar supports displayMode. ProgressBar colors are accent, good, warning, or attention, and badges are circular by default. - Line chart values are objects, and a missing y is 0. - What used to need extra properties is now how charts render: lines are smooth and filled, and a line chart narrower than 400 pixels draws as a sparkline. The Performance Monitor cards follow: history charts send only real samples, top processes are rows of text and progress bars, and the battery gauge uses segments. The Samples page and the author docs list only schema properties. Checked every element of the expanded cards against the element reference: 1,538 elements with no problems, where the cards before this change had 669.
|
This is beautiful |
|
Whoa! |
Gleb Khmyznikov (khmyznikov)
left a comment
There was a problem hiding this comment.
Automated review generated with .github/prompts/review-pr.prompt.md (Copilot CLI).
Full review of all 118 files at 6ef65d69ed. No high-severity issues; the incremental patching of chart elements, host-config refresh, template bindings/resources, and the new Performance Monitor data readers check out.
Findings: 0 high, 1 medium, 2 low (inline below).
- Medium: high contrast collapses every chart series/slice/segment to the same system color.
- Low: unsupported
Iconnames render nothing and ignorefallback(docs say to rely on it); the skill reference's accent-color default doesn't match the code.
Info (no action needed): the new host config also changes padding/spacing/separator thickness for every extension card (AdaptiveHostConfigJson.cs:18-29); K/M/B/T axis suffixes are hard-coded; the PR could follow the split the description proposes.
|
Jiří Polášek (@jiripolasek) I know you've worked one something similar. Input? |
- In high contrast, data colors cycle by index through the system Highlight, Hotlight, and WindowText colors instead of using Highlight for every item, and line series alternate solid, dashed, and dotted strokes. - Docs: uncolored items take colors from colorSet (categorical by default), and unsupported Icon names render nothing in Command Palette; the fallback applies only in hosts without Icon support.
Mike Griese (zadjii-msft)
left a comment
There was a problem hiding this comment.
blocking as discussed in teams. Can't accept a PR of this size, no sir-ee
Redraw the Memory card with the native Adaptive Cards elements from the layers below: memory in use and available, a 60-second Chart.Line history, and a stacked bar that splits memory into in use, modified, standby, and free, as Task Manager does. Tiles show committed, cached, paged pool, and non-paged pool memory. The card also shows the memory hardware, as Task Manager's memory page does: speed, slots used, and form factor from the SMBIOS memory devices, and hardware reserved memory from the installed memory. They are read once, since they don't change while Windows runs. Layer 6 of 13 in a stack that splits #51125.
Redraw the Disk card with the native Adaptive Cards elements from the layers below: active time, response time, and read and write speeds at the top, a 60-second Chart.Line history of the read and write rates, and the disk's name and type, such as Disk 0 (C:) and SSD (NVMe), as Task Manager's disk page shows them. Each volume on the disk gets a capacity bar that turns to warning at 85% full and attention at 95%. DiskStats now keeps one-second histories of active time and the read and write rates in SampleHistory, which the Network card will share, and reads the average response time from the Avg. Disk sec/Transfer counter. The disk type comes from a device property query that needs no elevation, read once per disk. The list item now names the disk as the card does: Disk 0 (C:) instead of Disk (0 C:). Layer 8 of 13 in a stack that splits #51125.
Adds the Chart.Gauge, Chart.Donut, and Chart.Pie elements to the Adaptive Cards polyfills library. The WinUI 3 renderer doesn't support them yet. - A gauge fills its arc up to the value, in the color of the segment that the value falls in, and draws the segments as a thin scale inside it. It can show a needle, min and max labels, and a legend, and its value as a percentage or a fraction. - Donut and pie charts draw a slice for each data point, with a legend of each slice's share. A donut can show a value in its center. - Untitled charts get the accessible name "Gauge", "Donut chart", or "Pie chart", from three new strings in Resources.resw. A gauge uses its sub label first. Layer 10 of 13 in a stack that splits #51125.
Corrects five claims in charts-and-visuals.md that didn't match the polyfills code, checked against the code and in the local card harness: - A line chart draws as a sparkline only when it's narrower than 400 pixels. The Tiles example had one tile that spans the card, which draws in full; it now has three tiles in a row, which draw sparklines. - Chart.HorizontalBar draws xAxisTitle and yAxisTitle only in the default AbsoluteWithAxis mode. - Without yMin and yMax, the axis of a line or vertical bar chart doesn't fit the data: it starts at 0, or lower for negative data, and its top rounds up to a grid line. - Chart.VerticalBar thins its labels so that their centers are at least 56 pixels apart, without measuring them, so long labels can still overlap. - On the Samples page, only the line chart, the gauge, and the progress bar under it update live. The page's subtitle in the Samples list said badges were live too. Layer 13 of 13 in a stack that splits #51125.
…ilds (#51204) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request **This PR is layer 1 of 13 in a stack.** The stack divides #51125 (native Adaptive Cards charts and new Performance Monitor cards) into smaller PRs. Refer to #51125 for the full design. This layer starts from `main`. It changes only `Microsoft.CmdPal.AdaptiveCards.IncrementalRendering` and its tests. This PR corrects two faults in the incremental updater for Adaptive Cards: - **Release builds do not update cards in place.** Under native AOT, the updater cannot read the element tags of the renderer. As a result, each update replaces the full card. - **Custom elements cannot update in place.** With this PR, a host can register custom element types. The controls of these types accept new data directly. Layer 2 (the chart polyfills library) uses this feature. Thus, live charts scroll, and the updater does not replace the card each second. ## Detailed Description of the Pull Request / Additional comments ### The fault in release builds Release builds compile Command Palette with native AOT. `.pipelines/v2/release.yml` sets `/p:EnableCmdPalAOT=true`. This property turns on `PublishAot` for `Microsoft.CmdPal.UI`. CI builds do not use native AOT. Thus, PR validation does not test this path. The updater uses element tags to find the controls that it can patch. A patchable control is a `TextBlock` or `Image` whose `Tag` is an `ElementTagContent` for an `AdaptiveTextBlock` or `AdaptiveImage`. Under native AOT, CsWinRT needs type metadata to identify an object that it receives as `object` or as a base type. No code kept this metadata. As a result, element tags came back as bare `IInspectable` objects. Text runs came back as `Inline`, not as `Run`. The fingerprint then treated all text and images as structure, and each update replaced the full card. The fix adds `[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(...))]` to the methods that read tags and runs. The attribute keeps the metadata for `ElementTagContent`, `AdaptiveTextBlock`, `AdaptiveImage`, and `Run`. I found this fault in #51125 with a native AOT build of a local card harness. The Performance Monitor cards in `main` show the same fault (refer to Validation). ### Patches for custom elements - `IncrementalPatchableElements` (new) is the list of custom element types that the updater can patch. `Add(type, rendersItself)` is for a type whose renderer sometimes shows the `fallback`. - `IIncrementalAdaptiveElementControl` (new) is the interface for the control of the element. The control gives a deterministic `IncrementalState`. First, the updater calls `CanApplyIncrementalState` on all changed controls. Then it calls `ApplyIncrementalState`. - `IncrementalAdaptiveCardUpdater` gets the registration through a new optional constructor parameter. Existing callers, for example `ContentFormControl`, do not change. Without a registration, the behavior does not change, except for the AOT fix. - `AdaptiveCardSemanticFingerprint` does not include the data of a registered element. Thus, a data change patches the control and does not replace the card. A change to a host-owned property (`id`, `isVisible`, `spacing`, `height`, or the actions) still replaces the card. - Fallbacks: A registered element that renders itself never shows its `fallback`. Thus, the updater ignores changes in that fallback, unless the element has `requires`. If an element shows its fallback, the updater cannot patch a fallback root that is a `TextBlock` or `Image`. The updater can patch text in a fallback container. - `README.md` tells how to register and implement a patchable element. The examples use `Chart.Line` and `Icon`, which layers 2 and 3 add. No code in Command Palette registers a patchable element yet. Layer 2 does this. The UI does not change, so this PR has no screenshots.
Adds a "Charts and visuals" page to the Samples extension. It shows every element that the Adaptive Cards polyfills render natively, each with a fallback for other hosts: a line chart, a gauge, donut and pie charts, and vertical, horizontal, and stacked bar charts in rounded, bordered tiles, followed by progress bars, badges, and icons. The line chart, the gauge, and the progress bar under it update every second. For extension authors, the template's add-adaptive-card-form skill now covers charts, and its new references/charts-and-visuals.md describes each element: its properties, colors, how to bind and update live data, and what Command Palette doesn't support yet. The polyfills README points authors to both, and its steps for adding an element now end with documenting it and adding it to the Samples extension. Layer 13 of 13 in a stack that splits #51125.
Corrects five claims in charts-and-visuals.md that didn't match the polyfills code, checked against the code and in the local card harness: - A line chart draws as a sparkline only when it's narrower than 400 pixels. The Tiles example had one tile that spans the card, which draws in full; it now has three tiles in a row, which draw sparklines. - Chart.HorizontalBar draws xAxisTitle and yAxisTitle only in the default AbsoluteWithAxis mode. - Without yMin and yMax, the axis of a line or vertical bar chart doesn't fit the data: it starts at 0, or lower for negative data, and its top rounds up to a grid line. - Chart.VerticalBar thins its labels so that their centers are at least 56 pixels apart, without measuring them, so long labels can still overlap. - On the Samples page, only the line chart, the gauge, and the progress bar under it update live. The page's subtitle in the Samples list said badges were live too. Layer 13 of 13 in a stack that splits #51125.
…ilds (#51204) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request **This PR is layer 1 of 13 in a stack.** The stack divides #51125 (native Adaptive Cards charts and new Performance Monitor cards) into smaller PRs. Refer to #51125 for the full design. This layer starts from `main`. It changes only `Microsoft.CmdPal.AdaptiveCards.IncrementalRendering` and its tests. This PR corrects two faults in the incremental updater for Adaptive Cards: - **Release builds do not update cards in place.** Under native AOT, the updater cannot read the element tags of the renderer. As a result, each update replaces the full card. - **Custom elements cannot update in place.** With this PR, a host can register custom element types. The controls of these types accept new data directly. Layer 2 (the chart polyfills library) uses this feature. Thus, live charts scroll, and the updater does not replace the card each second. ## Detailed Description of the Pull Request / Additional comments ### The fault in release builds Release builds compile Command Palette with native AOT. `.pipelines/v2/release.yml` sets `/p:EnableCmdPalAOT=true`. This property turns on `PublishAot` for `Microsoft.CmdPal.UI`. CI builds do not use native AOT. Thus, PR validation does not test this path. The updater uses element tags to find the controls that it can patch. A patchable control is a `TextBlock` or `Image` whose `Tag` is an `ElementTagContent` for an `AdaptiveTextBlock` or `AdaptiveImage`. Under native AOT, CsWinRT needs type metadata to identify an object that it receives as `object` or as a base type. No code kept this metadata. As a result, element tags came back as bare `IInspectable` objects. Text runs came back as `Inline`, not as `Run`. The fingerprint then treated all text and images as structure, and each update replaced the full card. The fix adds `[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(...))]` to the methods that read tags and runs. The attribute keeps the metadata for `ElementTagContent`, `AdaptiveTextBlock`, `AdaptiveImage`, and `Run`. I found this fault in #51125 with a native AOT build of a local card harness. The Performance Monitor cards in `main` show the same fault (refer to Validation). ### Patches for custom elements - `IncrementalPatchableElements` (new) is the list of custom element types that the updater can patch. `Add(type, rendersItself)` is for a type whose renderer sometimes shows the `fallback`. - `IIncrementalAdaptiveElementControl` (new) is the interface for the control of the element. The control gives a deterministic `IncrementalState`. First, the updater calls `CanApplyIncrementalState` on all changed controls. Then it calls `ApplyIncrementalState`. - `IncrementalAdaptiveCardUpdater` gets the registration through a new optional constructor parameter. Existing callers, for example `ContentFormControl`, do not change. Without a registration, the behavior does not change, except for the AOT fix. - `AdaptiveCardSemanticFingerprint` does not include the data of a registered element. Thus, a data change patches the control and does not replace the card. A change to a host-owned property (`id`, `isVisible`, `spacing`, `height`, or the actions) still replaces the card. - Fallbacks: A registered element that renders itself never shows its `fallback`. Thus, the updater ignores changes in that fallback, unless the element has `requires`. If an element shows its fallback, the updater cannot patch a fallback root that is a `TextBlock` or `Image`. The updater can patch text in a fallback container. - `README.md` tells how to register and implement a patchable element. The examples use `Chart.Line` and `Icon`, which layers 2 and 3 add. No code in Command Palette registers a patchable element yet. Layer 2 does this. The UI does not change, so this PR has no screenshots. (cherry picked from commit 28acb1b) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ames (#51206) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Independent PR split out of #51125, which redesigns the Performance Monitor cards; see it for the full picture. This PR can merge in any order with the rest of that split. It fixes two Performance Monitor bugs on `main`: - **A metric shown in two places records its history at double speed.** For example, with the Memory dock band pinned and the Performance Monitor page open, two one-second timers each add a point to the same chart history, so the chart fills twice as fast and covers half the time it should. Now every metric (CPU, memory, network, disk, GPU, and battery) gets one sample per second, however many places show it. - **Some GPU names make the dock label too long.** Some drivers append details in parentheses: `NVIDIA RTX Spark N1X (6144-core Blackwell RTX GPU)` showed as `RTX Spark N1X (6144-core Blackwell RTX GPU)`. It now shows as `RTX Spark N1X`. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: N/A. Split out of #51125. <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end-user-facing strings can be localized (no new strings) - [ ] **Dev docs:** Added/updated (N/A) - [ ] **New binaries:** Added on the required places (N/A: no new binaries or projects) - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx (N/A) <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments ### Double-speed histories On `main`, `PerformanceMonitorCommandsProvider` creates the main page, the combined dock band, and a dock band for each metric. Each is a `PerformanceWidgetsPage` with its own `SystemXxxUsageWidgetPage` for each metric it shows, and each of those has its own `DataManager` with a one-second timer that runs while the page or band is shown. Every `DataManager` samples the same `SystemData.Shared` stats, and for CPU, memory, network, disk, and GPU, each sample appends a point to the shared chart history (`ChartHelper.AddNextChartValue`). So each extra place that shows a metric adds another point per second. `DataManager.ShouldSample` records when each stats object was last sampled, in a `ConditionalWeakTable` keyed by the stats object, and skips the sample if the last one was less than 750 ms ago. The check runs under the stats lock that each sampler already takes. 750 ms leaves room for timer jitter: a late tick from the same timer still samples, but a second timer's tick within the same second doesn't. Every timer still calls its page's update, so every place keeps showing the latest values. All six metrics are gated: CPU, memory, network, disk, GPU, and battery. Every CPU page on `main` uses `DataType.CPU`, so all CPU timers ask for the same sample; `includeTopProcesses` and `DataType.CpuWithTopProcesses` are unchanged. ### Long GPU names `GpuAdapterNames.GetShortName` removes known branding, such as `NVIDIA`, `GeForce`, `(R)`, `(TM)`, and a trailing ` GPU`. Nothing removed a trailing part in parentheses, so it stayed in the label. It's now dropped before the other rules run, so they see the model name. Names without one are unchanged. ### Tests - `DataManagerTests` (new) covers `ShouldSample`: the first sample, a second timer within the same second, a late tick, and separate schedules for each stats object. - `GpuAdapterNamesTests` gets a row for `NVIDIA RTX Spark N1X (6144-core Blackwell RTX GPU)`. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed ARM64, Debug, from the repo root: - `MSBuild.exe src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.PerformanceMonitor\Microsoft.CmdPal.Ext.PerformanceMonitor.csproj -nologo -m -restore -t:Build -v:minimal -p:Configuration=Debug -p:Platform=ARM64 -p:RuntimeIdentifier=win-arm64 -p:CIBuild=false -p:GeneratePackageLocally=false -p:GenerateAppxPackageOnBuild=false -p:PublishAppxPackage=false -p:SkipLongPathsCheck=true`: exit code 0, 0 warnings. - The same command for `src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.PerformanceMonitor.UnitTests\Microsoft.CmdPal.Ext.PerformanceMonitor.UnitTests.csproj`: exit code 0, 0 warnings. - `vstest.console.arm64.exe ARM64\Debug\WinUI3Apps\CmdPal\tests\Microsoft.CmdPal.Ext.PerformanceMonitor.UnitTests.dll /Platform:ARM64`: 103 passed, 0 failed, including the four new `DataManagerTests` and the new GPU name row. - With `main`'s `GpuAdapterNames.cs`, the new GPU name row fails: `Expected:<RTX Spark N1X>. Actual:<RTX Spark N1X (6144-core Blackwell RTX GPU)>`. - A throwaway test (not in this PR) reproduced the double-speed history. It called the samplers of two `DataManager` instances for the same metric 500 ms apart, once per second each, for 5 seconds, with the real `MemoryStats` and `CPUStats`: | Metric | History points without this PR | With this PR | |---|---|---| | Memory | 10 | 5 | | CPU | 10 | 5 |
Summary of the Pull Request
The Performance Monitor cards in the Command Palette dock looked rough: each chart was a fixed 268x86 SVG image, values were pinned to the card's edges, and most of the card was empty. This PR rebuilds them as Task Manager-style dashboards and keeps them plain Adaptive Cards: no fork of the renderer, no new dependencies, and card JSON that uses only what the Adaptive Cards schema defines.
Chart.Line,Chart.Gauge,Chart.Donut,Chart.Pie,Chart.VerticalBar,Chart.HorizontalBar,Chart.HorizontalBar.Stacked,ProgressBar,Badge, andIconwith native WinUI controls, through the WinUI 3 renderer's public custom element APIs. Every extension can use them, with afallbackfor other hosts. They're in a new library,Microsoft.CmdPal.AdaptiveCards.Polyfills, with nothing specific to Command Palette in it, so each one can move to the renderer upstream and be deleted here.roundedCornersandshowBorder.Every card in dark and light, the Samples gallery, high contrast, and Icon fallback
The screenshots come from a local harness that renders the real templates and live data through the same renderer and controls, at the dock window's content width. The Network card's addresses are replaced with documentation addresses, and the "before" images are from #50720. The harness can't switch the system to a contrast theme, so the high contrast images use the colors from each contrast theme's
.themefile. Progress bars take their color from the app's theme resources, so there they still show the accent color.PR Checklist
Microsoft.CmdPal.AdaptiveCards.Polyfills.dllships inside the Command Palette MSIX, which is what's signed, and CI runs every*UnitTest*project, so likeMicrosoft.CmdPal.AdaptiveCards.IncrementalRenderingit only needed solution entries, not these:Detailed Description of the Pull Request / Additional comments
How it fits together
Microsoft.CmdPal.AdaptiveCards.Polyfills, a new class library: one model and one control per element,roundedCornersandshowBorderfor containers, and the fallback workaround below. Models parse the element JSON without WinUI, so unit tests cover them directly (Microsoft.CmdPal.AdaptiveCards.Polyfills.UnitTests), and controls draw with XAML shapes, built in code. Command Palette registers it with three calls inContentFormControland passes in the chart strings, which stay in itsResources.resw. The README explains the pieces, how to add an element, and how to delete each one when the renderer supports it.AdaptiveCardsConfig,AdaptiveCardThemeTokens, andAdaptiveHostConfigJsonbuild the host config, cached per theme, andContentFormControl.xamlhas the theme-aware container styles thatroundedCornersandshowBorderapply. These are Command Palette's design, so they stay inMicrosoft.CmdPal.UI.Microsoft.CmdPal.AdaptiveCards.IncrementalRendering: registered elements implementIIncrementalAdaptiveElementControl, so the updater moves new data into the existing control, and their data no longer counts toward the card's semantic fingerprint.PerformanceChartData,ProcessCpuSampler,MemoryHardware,DiskVolumes,NetworkConnectionDetails, and more), an Overview page and dock band, and one shared sample per second for each metric.references/charts-and-visuals.mdin the extension template'sadd-adaptive-card-formskill, and a live "Charts and visuals" page in the Samples extension.Adaptive Cards compliance
The cards use only element types, properties, and values from the current element reference, and the renderers read nothing else. A script checked every element of the expanded cards (the seven Performance Monitor cards, the Samples page, and an
Iconfallback card) against the reference: 1,565 elements, no problems. Command Palette doesn't support all of the schema yet:Chart.VerticalBar.GroupedandProgressRingare dropped, even with a fallback (see the renderer bug below);thickness,valueColor,showOutlines,maxWidth, andIcon.selectActionare ignored; andIcondraws the 130 catalog names that have a matching Segoe Fluent Icons glyph, and the icon'sfallbackfor other names.Worth a careful look
main, the incremental updater never patches in place in release builds. Release builds use native AOT, where CsWinRT finds an object's type by name and needs its metadata. Element tags came back as bareIInspectableobjects, so every update rebuilt the whole card.03a557d3bbkeeps that metadata withDynamicDependency, and also fixes anInvalidCastExceptionin chart legends and the high contrast colors, which only failed under AOT.separator: truenow draws a line. The medium and extra large font sizes go from 14 and 26 to 16 and 28. The font changes from a web font stack to Segoe UI Variable, with Cascadia Mono for monospace, and colors come from theme resources instead of fixed values. Small and default spacing, image sizes, and action settings don't change.fallback.XamlBuilder::RenderAsUIElementrenders it and then returns an empty result (since [UWP Renderer] Allow nested fallbacks AdaptiveCards#8234). So onmaintoo, Command Palette drops an unknown element even when it has a fallback. Command Palette's own elements draw their fallback themselves (AdaptiveFallbackRenderer), which is how anIconwithout a glyph shows its fallback. The upstream fix is one line.AdaptiveCustomElementJson, frommain, moves into the new library and becomes public, since both the library's elements and Command Palette's settings inputs use it.fallback.yis a number with no "missing" value, so a history that's still filling up spans the whole chart until 60 samples arrive. Dock bands sample while the dock is visible, so a card opened from the dock usually has a full history.Also fixed along the way:
Disk (0 C:)while its card saidDisk 0 (C:).Found while testing, not changed here
Microsoft.CmdPal.UI.ViewModels.Dock.DockBandViewModelin UI Automation, and the dock buttons can't be invoked, so screen readers can't use the dock.DockSettings.Sideloads the dock on the left, although the default is the top.Size and where to look
29 commits, mostly one per step: +12,558 and −1,127 lines in 130 files. About half is generic Adaptive Cards code that any host could use, and the rest is Command Palette's. About 6,100 of the added lines are C# code outside the tests, with about 560 lines of comments. The last two commits move the generic code into its own library; the first of them only moves files.
NativeMethods.txt, and the project fileFor review, this could split along the projects: (1) the polyfills library and its tests; (2) the host config and Command Palette's wiring; (3) the Performance Monitor cards and data, with the samples.
Validation Steps Performed
On an ARM64 Windows 11 machine, with the final code:
MSBuild.exe <project> -nologo -m -restore -v:minimal -p:Configuration=Debug -p:Platform=ARM64 -p:RuntimeIdentifier=win-arm64 -p:CIBuild=false -p:GeneratePackageLocally=false -p:GenerateAppxPackageOnBuild=false -p:PublishAppxPackage=false -p:SkipLongPathsCheck=trueforMicrosoft.CmdPal.AdaptiveCards.Polyfills,Microsoft.CmdPal.UI,SamplePagesExtension, and the four test projects below: exit code 0. These projects run the trim and AOT analyzers, with warnings as errors.vstest.console.arm64.exe ARM64\Debug\WinUI3Apps\CmdPal\tests\Microsoft.CmdPal.UI.UnitTests.dll /Platform:ARM64: 686 passed.vstest.console.arm64.exe ARM64\Debug\WinUI3Apps\CmdPal\tests\Microsoft.CmdPal.AdaptiveCards.Polyfills.UnitTests.dll /Platform:ARM64: 128 passed (the chart tests, which were in the UI tests before the move).vstest.console.arm64.exe ARM64\Debug\WinUI3Apps\CmdPal\tests\Microsoft.CmdPal.AdaptiveCards.IncrementalRendering.UnitTests.dll /Platform:ARM64: 43 passed.vstest.console.arm64.exe ARM64\Debug\WinUI3Apps\CmdPal\tests\Microsoft.CmdPal.Ext.PerformanceMonitor.UnitTests.dll /Platform:ARM64: 166 passed.-p:Configuration=Release -p:Platform=x64 -p:RuntimeIdentifier=win-x64for the library's tests (which build the library),Microsoft.CmdPal.UI, and the UI tests: exit code 0.Iconfallback card in the harness:Calendardraws its glyph, andBotdraws aTextBlockfallback, aContainerfallback whose text updates, or nothing withdrop. 14 updates, none of them full replacements.Iconfallback card.Iconfallback card: identical in dark and light, apart from anti-aliasing that differs by one level and the indeterminate progress bar's animation. With the contrast themes' colors, only the line chart changed: its axis labels and grid lines take the contrast theme's text color, as they already did in a real contrast theme through the XAML resources it no longer uses.6ef65d69ed) had 669 problems, such asnullsamples, chart properties that the schema doesn't define, and chart colors on progress bars..pipelines\verifyCommonProps.ps1.Microsoft.CommandPalette.Dev, registered from the build output), light theme: it loadsMicrosoft.CmdPal.AdaptiveCards.Polyfills.dllfrom its package folder, and the Overview, CPU, Memory, GPU, Network, and Battery cards opened from the real dock draw every chart natively: line charts and sparklines, the per-processor bar chart, the top process bars, the memory composition bar, the restyled battery gauge, icons, and badges.6ef65d69ed, the packaged app, cards opened from the real dock: the CPU card patches in place (the same UI Automation element, with its up time changing); the Battery card shows the segmented gauge, and no discharge rate while plugged in.Earlier in the branch:
4c07d44cbe), x64 Release builds of the UI and the test projects passed, and so did their tests.870941431f, every card was opened from the real dock in the packaged app, and all rendered.Not verified yet in the packaged app: dark theme, a real contrast theme, and 150% scale. Also not done: a native AOT publish of Command Palette itself.