mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-08-29 10:09:43 +02:00
Tighten Phase 7 protocol additions
Document details sizing and deferred prefix selection, constrain numeric size values, and encode the bundled image through the SDK helper. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -234,7 +234,9 @@ public class JSAdapterProxyTests
|
||||
"items": [
|
||||
{ "title": "Large by name", "details": { "title": "A", "size": "large" } },
|
||||
{ "title": "Medium by number", "details": { "title": "B", "size": 1 } },
|
||||
{ "title": "Default size", "details": { "title": "C" } }
|
||||
{ "title": "Default size", "details": { "title": "C" } },
|
||||
{ "title": "Unknown name", "details": { "title": "D", "size": "extra-large" } },
|
||||
{ "title": "Unknown number", "details": { "title": "E", "size": 99 } }
|
||||
]
|
||||
}
|
||||
""";
|
||||
@@ -247,6 +249,8 @@ public class JSAdapterProxyTests
|
||||
Assert.AreEqual((int)ContentSize.Large, GetDetailsSize(items[0].Details));
|
||||
Assert.AreEqual((int)ContentSize.Medium, GetDetailsSize(items[1].Details));
|
||||
Assert.AreEqual((int)ContentSize.Small, GetDetailsSize(items[2].Details));
|
||||
Assert.AreEqual((int)ContentSize.Small, GetDetailsSize(items[3].Details));
|
||||
Assert.AreEqual((int)ContentSize.Small, GetDetailsSize(items[4].Details));
|
||||
}
|
||||
|
||||
private static int GetDetailsSize(IDetails? details)
|
||||
|
||||
@@ -287,8 +287,11 @@ interface Details {
|
||||
title?: string;
|
||||
body?: string; // Markdown-formatted body text
|
||||
metadata?: DetailsElement[];
|
||||
size?: DetailsSize; // Defaults to 'small'
|
||||
}
|
||||
|
||||
type DetailsSize = 'small' | 'medium' | 'large' | 0 | 1 | 2;
|
||||
|
||||
interface DetailsElement {
|
||||
key: string; // Label shown to the left
|
||||
data: DetailsData; // Value shown to the right
|
||||
@@ -302,6 +305,10 @@ type DetailsData =
|
||||
| DetailsSeparator; // { type: 'separator' }
|
||||
```
|
||||
|
||||
Use the named sizes for new extensions. The numeric values map to the host's
|
||||
`ContentSize` values and remain available when you need to mirror an existing
|
||||
host payload.
|
||||
|
||||
---
|
||||
|
||||
## Page Types
|
||||
|
||||
@@ -246,6 +246,7 @@ Fetches items for a list page.
|
||||
"details": {
|
||||
"title": "Item One Details",
|
||||
"body": "**Rich** markdown description",
|
||||
"size": "large",
|
||||
"metadata": [
|
||||
{ "key": "Author", "data": { "type": "tags", "tags": [{ "text": "mjolley" }] } },
|
||||
{ "key": "Link", "data": { "type": "link", "link": "https://github.com", "text": "GitHub" } }
|
||||
@@ -266,6 +267,10 @@ Fetches items for a list page.
|
||||
|
||||
`hasMoreItems` is a boolean on the response envelope (it defaults to `false` when the extension omits it). `true` tells the host that more pages remain, so the host may issue a [`listPage/loadMore`](#listpageloadmore) request when the user scrolls to the end; `false` means the current items are the full set. The value comes straight from the list page's `hasMoreItems` property.
|
||||
|
||||
The optional `details.size` field accepts `small`, `medium`, or `large`. The
|
||||
matching host `ContentSize` values `0`, `1`, and `2` are also accepted. Missing
|
||||
or unknown values use `small`.
|
||||
|
||||
The `section` field is ignored on any item that carries a command. The host renders a command-bearing item as a normal list item, so it never becomes a group header. `section` takes effect only on a command-less row, where it turns that row into a section header. To group command items visually, emit a standalone separator row (see below) before the group.
|
||||
|
||||
Items with `_isSeparator: true` are rendered as visual separators:
|
||||
|
||||
@@ -79,6 +79,20 @@ There is no per-page unload notification. A JS page learns it has become active
|
||||
|
||||
A future solution would be additive and JS-only: a host to extension JSON-RPC notification (for example `page/unloaded` carrying the page id, and optionally a symmetric `page/loaded`), emitted from the host where a page is torn down. `PageViewModel.UnsafeCleanup` is the natural single choke point, since back-navigation and other disposal paths all pass through it. The TS SDK would expose an optional `onUnload` (and optionally `onLoad`) hook on the page base classes, following the existing `loadMore` lifecycle pattern. Because it is additive with no reply expected, older extensions that do not register the hook are unaffected. The item is deferred because it introduces JS-only surface with no C# ABI equivalent, and that asymmetry needs a broader decision.
|
||||
|
||||
### Prefixed token selection
|
||||
|
||||
`textToSuggest` supports whole-query completion, but it does not provide the
|
||||
native sample's token behavior. The native path opts into `TokenSearch`, tracks
|
||||
the caret, wraps selected tokens with zero-width spaces, and lets the search box
|
||||
delete a token as one unit. None of that state crosses the JSON-RPC boundary
|
||||
today, so the JS sample does not pretend that right-arrow completion is the same
|
||||
feature.
|
||||
|
||||
A future design can stay additive. A list page could opt into token search, and
|
||||
`listPage/setSearchText` could include an optional caret position. The host and
|
||||
SDK would still need an agreed token shape before exposing selection because
|
||||
zero-width-space markers are an implementation detail, not a wire contract.
|
||||
|
||||
### Drag and drop (DataPackage)
|
||||
|
||||
There is no drag-and-drop or `DataPackage` concept anywhere in the extension ABI, in either the C# or the JS surface. The only related primitive today is the clipboard, exposed through `IExtensionHost.copyToClipboard`. Items cannot declare draggable payloads, and the host list and content controls do not act as drag sources or drop targets for extension data.
|
||||
|
||||
@@ -43,6 +43,8 @@ inventing protocol methods:
|
||||
- Parameter pages (`SimpleParameterTest`, `ButtonParameterTest`,
|
||||
`MixedParamTestPage`) and the create-note list-parameter page. No parameter
|
||||
run protocol.
|
||||
- Prefixed token selection. `textToSuggest` can complete the whole query, but
|
||||
token search state and caret position do not cross the JSON-RPC boundary.
|
||||
- Drag and drop via `DataPackage`. `IListItem` has no `DataPackage`, so the
|
||||
clipboard demo copies to the clipboard instead.
|
||||
- Toast icon and toast action button (`IToastArgs2`). `ToastArgs` carries a
|
||||
|
||||
@@ -113,13 +113,8 @@ export class SamplePlainTextContentPage extends ContentPageBase {
|
||||
/**
|
||||
* A page showing images. Mirrors the C# `SampleImageContentPage`.
|
||||
*
|
||||
<<<<<<< HEAD
|
||||
* The C# page loads packaged JPG and SVG assets. This sample uses its bundled
|
||||
* hero PNG and sends the encoded image bytes rather than a machine-specific path.
|
||||
=======
|
||||
* The image ships with the sample, so the page works without a network
|
||||
* connection and matches the details page.
|
||||
>>>>>>> d644f02e36 (reword phase-7 comments in my voice)
|
||||
*/
|
||||
export class SampleImageContentPage extends ContentPageBase {
|
||||
readonly id = 'sample-image-content-page';
|
||||
|
||||
@@ -106,7 +106,7 @@ channel. Your logging is preserved on `stderr` and through
|
||||
- Icons and colors: `IconData`, `IconInfo`, `Color`, `OptionalColor`, `Tag`, `KeyChord`.
|
||||
- Commands and results: `ICommand`, `IInvokableCommand`, `CommandResult`, `CommandResultKind`, `NavigationMode`.
|
||||
- Items: `ICommandItem`, `IListItem`, `IFallbackCommandItem`, `ContextItem`.
|
||||
- Details panel: `Details`, `DetailsElement`, and the `DetailsData` union (`tags`, `link`, `commands`, `separator`).
|
||||
- Details panel: `Details`, `DetailsSize`, `DetailsElement`, and the `DetailsData` union (`tags`, `link`, `commands`, `separator`).
|
||||
- Pages: `IPage`, `IListPage`, `IDynamicListPage`, `IContentPage`, `Filters`, `GridProperties`.
|
||||
- Content: the `Content` union (`markdown`, `form`, `tree`, `plainText`, `image`).
|
||||
- Settings and host: `ICommandSettings`, `IExtensionHost`, `ICommandProvider`.
|
||||
|
||||
@@ -32,7 +32,7 @@ export type ContentType = 'markdown' | 'form' | 'tree' | 'plainText' | 'image';
|
||||
export type GridLayoutType = 'small' | 'medium' | 'gallery';
|
||||
|
||||
/** Size of the details pane shown alongside a list item or content page. */
|
||||
export type DetailsSize = 'small' | 'medium' | 'large';
|
||||
export type DetailsSize = 'small' | 'medium' | 'large' | 0 | 1 | 2;
|
||||
|
||||
/** Font family used by plain text content. */
|
||||
export type FontFamily = 'userInterface' | 'monospace';
|
||||
@@ -349,11 +349,11 @@ export interface Details {
|
||||
/** Labeled metadata rows shown below the body. */
|
||||
metadata?: DetailsElement[];
|
||||
/**
|
||||
* Size of the details pane. You can send 'small', 'medium', or 'large'.
|
||||
* Numeric `ContentSize` values (0, 1, 2) also work to match the host.
|
||||
* Size of the details pane. Named values are preferred, and the matching
|
||||
* numeric `ContentSize` values are accepted for host compatibility.
|
||||
* Omitted values default to 'small'.
|
||||
*/
|
||||
size?: DetailsSize | number;
|
||||
size?: DetailsSize;
|
||||
}
|
||||
|
||||
// === Filters ===
|
||||
|
||||
@@ -144,4 +144,3 @@ describe('WireSerializer.commandItem fallback ids', () => {
|
||||
expect(new WireSerializer().commandItem(item).id).toBe('fallback-command');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user