From 14867d7b10a8118d3cc3fbafd000572356faff0e Mon Sep 17 00:00:00 2001 From: Brian Leighty Date: Wed, 27 Mar 2024 13:38:52 -0400 Subject: [PATCH] Split panel scenegraph inspector (#555) * disable screensaver by default * update Loader component to use vscode-progress-ring * add TreeNodeWithBase type * Move all webviews into vscode-brightscript-language tab * finish split panel scenegraph inspector * final cleanup * upgrade roku-test-automation to 2.04 * upgrade roku-test-automation to 2.04 --------- Co-authored-by: Brian Leighty Co-authored-by: Bronley Plumb --- package-lock.json | 14 +- package.json | 2 +- src/managers/RtaManager.ts | 2 +- src/viewProviders/BaseRdbViewProvider.ts | 9 + .../SceneGraphInspectorViewProvider.ts | 10 - webviews/src/ExtensionIntermediary.ts | 2 +- webviews/src/shared/Loader.svelte | 32 +- webviews/src/shared/types.ts | 5 + .../RokuDeviceView/RokuDeviceView.svelte | 63 +- .../SceneGraphInspectorView/Branch.svelte | 107 +-- .../NodeDetailPage.svelte | 642 ++++++++++-------- .../SceneGraphInspectorView.svelte | 173 +++-- 12 files changed, 601 insertions(+), 460 deletions(-) diff --git a/package-lock.json b/package-lock.json index fdf97442..80663032 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "pretty-bytes": "^5.6.0", "roku-debug": "^0.21.6", "roku-deploy": "^3.12.0", - "roku-test-automation": "2.0.0-beta.22", + "roku-test-automation": "^2.0.4", "semver": "^7.1.3", "source-map": "^0.7.3", "thenby": "^1.3.4", @@ -8973,9 +8973,9 @@ } }, "node_modules/roku-test-automation": { - "version": "2.0.0-beta.22", - "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.0-beta.22.tgz", - "integrity": "sha512-dyUHqlfjdimta06MmdQXQyEuKyVdXjKTzZ4rczZ57CsAaWlsqTdmA1JD+bYsyq9NdNzNrQWz1cuR93Oo632MNA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.4.tgz", + "integrity": "sha512-WhyBDQp10Y5ETr9up90HRmBsjWRfr6scbHMhHEGE1WfA3WkcZglc/6FZ9L3MWMr+jDOc693u4wvue3cWNhPyYw==", "dependencies": { "@suitest/types": "^4.6.0", "ajv": "^6.12.6", @@ -17917,9 +17917,9 @@ } }, "roku-test-automation": { - "version": "2.0.0-beta.22", - "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.0-beta.22.tgz", - "integrity": "sha512-dyUHqlfjdimta06MmdQXQyEuKyVdXjKTzZ4rczZ57CsAaWlsqTdmA1JD+bYsyq9NdNzNrQWz1cuR93Oo632MNA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/roku-test-automation/-/roku-test-automation-2.0.4.tgz", + "integrity": "sha512-WhyBDQp10Y5ETr9up90HRmBsjWRfr6scbHMhHEGE1WfA3WkcZglc/6FZ9L3MWMr+jDOc693u4wvue3cWNhPyYw==", "requires": { "@suitest/types": "^4.6.0", "ajv": "^6.12.6", diff --git a/package.json b/package.json index d0e322be..7eeb5faa 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "pretty-bytes": "^5.6.0", "roku-debug": "^0.21.6", "roku-deploy": "^3.12.0", - "roku-test-automation": "2.0.0-beta.22", + "roku-test-automation": "^2.0.4", "semver": "^7.1.3", "source-map": "^0.7.3", "thenby": "^1.3.4", diff --git a/src/managers/RtaManager.ts b/src/managers/RtaManager.ts index 5af9a3e3..66ccd8dc 100644 --- a/src/managers/RtaManager.ts +++ b/src/managers/RtaManager.ts @@ -59,7 +59,7 @@ export class RtaManager { this.updateDeviceAvailabilityOnWebViewProviders(); - if (config.disableScreenSaver) { + if (config.disableScreenSaver !== false) { void this.onDeviceComponent?.disableScreenSaver({ disableScreensaver: true }); } } diff --git a/src/viewProviders/BaseRdbViewProvider.ts b/src/viewProviders/BaseRdbViewProvider.ts index 83a70c5b..61505697 100644 --- a/src/viewProviders/BaseRdbViewProvider.ts +++ b/src/viewProviders/BaseRdbViewProvider.ts @@ -50,6 +50,15 @@ export abstract class BaseRdbViewProvider extends BaseWebviewViewProvider { }); return Promise.resolve(true); }); + + this.addMessageCommandCallback(ViewProviderCommand.getStoredNodeReferences, (message) => { + const response = this.dependencies.rtaManager.getStoredNodeReferences(); + this.postOrQueueMessage({ + ...message, + response: response + }); + return Promise.resolve(true); + }); } protected onViewReady() { diff --git a/src/viewProviders/SceneGraphInspectorViewProvider.ts b/src/viewProviders/SceneGraphInspectorViewProvider.ts index 73485d8c..0df62646 100644 --- a/src/viewProviders/SceneGraphInspectorViewProvider.ts +++ b/src/viewProviders/SceneGraphInspectorViewProvider.ts @@ -1,7 +1,6 @@ import type * as vscode from 'vscode'; import { BaseRdbViewProvider } from './BaseRdbViewProvider'; import { ViewProviderId } from './ViewProviderId'; -import { ViewProviderCommand } from './ViewProviderCommand'; export class SceneGraphInspectorViewProvider extends BaseRdbViewProvider { public readonly id = ViewProviderId.sceneGraphInspectorView; @@ -10,14 +9,5 @@ export class SceneGraphInspectorViewProvider extends BaseRdbViewProvider { super(context, dependencies); this.registerCommandWithWebViewNotifier(context, 'extension.brightscript.sceneGraphInspectorView.refreshNodeTree'); - - this.addMessageCommandCallback(ViewProviderCommand.getStoredNodeReferences, (message) => { - const response = this.dependencies.rtaManager.getStoredNodeReferences(); - this.postOrQueueMessage({ - ...message, - response: response - }); - return Promise.resolve(true); - }); } } diff --git a/webviews/src/ExtensionIntermediary.ts b/webviews/src/ExtensionIntermediary.ts index f1b396f6..3a30124c 100644 --- a/webviews/src/ExtensionIntermediary.ts +++ b/webviews/src/ExtensionIntermediary.ts @@ -1,9 +1,9 @@ /** Acts as a middle man that takes request from our views and sends them through vscode message protocol and waits for replies to simplify usage in code */ import type * as rta from 'roku-test-automation'; +import { RequestType } from 'roku-test-automation/client/dist/types/OnDeviceComponent'; import type { VscodeCommand } from '../../src/commands/VscodeCommand'; import type { ViewProviderEvent } from '../../src/viewProviders/ViewProviderEvent'; import { ViewProviderCommand } from '../../src/viewProviders/ViewProviderCommand'; -import { RequestType } from 'roku-test-automation/client/dist/types/OnDeviceComponent'; import type { DeleteEntireRegistrySectionsArgs, DeleteNodeReferencesArgs, DeleteRegistrySectionsArgs, FindNodesAtLocationArgs, GetFocusedNodeArgs, GetNodesInfoArgs, GetNodesWithPropertiesArgs, GetValueArgs, GetValuesArgs, HasFocusArgs, IsInFocusChainArgs, OnFieldChangeOnceArgs, ReadRegistryArgs, RequestOptions, SetValueArgs, StoreNodeReferencesArgs, WriteRegistryArgs, GetVolumeListArgs, GetDirectoryListingArgs, StatPathArgs, RenameFileArgs, DeleteFileArgs, CreateDirectoryArgs, RemoveNodeChildrenArgs } from 'roku-test-automation'; class ExtensionIntermediary { diff --git a/webviews/src/shared/Loader.svelte b/webviews/src/shared/Loader.svelte index e298d91f..2ded1808 100644 --- a/webviews/src/shared/Loader.svelte +++ b/webviews/src/shared/Loader.svelte @@ -1,28 +1,18 @@ -
-
+
+
diff --git a/webviews/src/shared/types.ts b/webviews/src/shared/types.ts index a384a413..1633a358 100644 --- a/webviews/src/shared/types.ts +++ b/webviews/src/shared/types.ts @@ -1,6 +1,11 @@ import type { odc } from '../ExtensionIntermediary'; +import type { TreeNode, BaseType } from 'roku-test-automation'; export type PathContentsInfo = Omit>>, 'type'> & { name: string; path: string; type?: 'file' | 'directory' | 'fileSystem'; }; + +export type TreeNodeWithBase = Partial & { + base?: keyof typeof BaseType; +}; diff --git a/webviews/src/views/RokuDeviceView/RokuDeviceView.svelte b/webviews/src/views/RokuDeviceView/RokuDeviceView.svelte index 680dd235..1f16a34f 100644 --- a/webviews/src/views/RokuDeviceView/RokuDeviceView.svelte +++ b/webviews/src/views/RokuDeviceView/RokuDeviceView.svelte @@ -5,9 +5,8 @@ import { ViewProviderId } from '../../../../src/viewProviders/ViewProviderId'; import { ViewProviderEvent } from '../../../../src/viewProviders/ViewProviderEvent'; import { ViewProviderCommand } from '../../../../src/viewProviders/ViewProviderCommand'; - import type { TreeNode } from 'roku-test-automation'; + import type { TreeNode, FindNodesAtLocationArgs } from 'roku-test-automation'; import { OnDeviceComponent } from 'roku-test-automation/client/dist/OnDeviceComponent'; - import type { FindNodesAtLocationArgs } from 'roku-test-automation/client/dist/types/OnDeviceComponent'; import { VscodeCommand } from '../../../../src/commands/VscodeCommand'; import { utils } from '../../utils'; @@ -73,37 +72,42 @@ let focusedTreeNode: TreeNode | null; $: { if (mouseIsOverView && isInspectingNodes) { - if (focusedTreeNode) { - if (lastFocusedTreeNodeRef !== focusedTreeNode.ref) { - lastFocusedTreeNodeRef = focusedTreeNode.ref; - - const treeNode = { - // Optimization since we only need the reference for linking with the sceneGraphInspectorView - ref: focusedTreeNode.ref - } - - const message = intermediary.createEventMessage(ViewProviderEvent.onTreeNodeFocused, { - treeNode: treeNode - }); - - intermediary.sendMessageToWebviews(ViewProviderId.sceneGraphInspectorView, message); - } - } else { - const message = intermediary.createEventMessage(ViewProviderEvent.onTreeNodeFocused, { - treeNode: null - }); + if (focusedTreeNode && lastFocusedTreeNodeRef !== focusedTreeNode.ref) { + lastFocusedTreeNodeRef = focusedTreeNode.ref; + sendOnTreeNodeFocusedEvent(focusedTreeNode); + } + } + } - intermediary.sendMessageToWebviews(ViewProviderId.sceneGraphInspectorView, message); + function sendOnTreeNodeFocusedEvent(treeNode, shouldOpen = false) { + if (!shouldOpen) { + treeNode = { + // Optimization since we only need the keyPath for linking with the sceneGraphInspectorView unless we are opening that node + keyPath: treeNode?.keyPath } } + const message = intermediary.createEventMessage(ViewProviderEvent.onTreeNodeFocused, { + // Keeping outer treeNode structure just so the events being sent from this view to the sceneGraphInspectorView are the same as we receive + treeNode: treeNode, + shouldOpen: shouldOpen + }); + intermediary.sendMessageToWebviews(ViewProviderId.sceneGraphInspectorView, message); } intermediary.observeEvent(ViewProviderEvent.onTreeNodeFocused, (message) => { focusedTreeNode = message.context.treeNode; }); - intermediary.observeEvent(ViewProviderEvent.onStoredNodeReferencesUpdated, (message) => { - focusedTreeNode = null; + intermediary.observeEvent(ViewProviderEvent.onStoredNodeReferencesUpdated, async (message) => { + if (focusedTreeNode) { + const result = await intermediary.getStoredNodeReferences(); + for (const treeNode of result.flatTree) { + if (treeNode.keyPath === focusedTreeNode.keyPath) { + focusedTreeNode = treeNode; + break; + } + } + } }); let nodeSelectionCursorLeft = 0; @@ -170,7 +174,6 @@ } lastFindNodesAtLocationArgs = args; - const {matches} = await onDeviceComponent.findNodesAtLocation(args); focusedTreeNode = matches[0]; } @@ -184,6 +187,11 @@ } function onMouseDown() { + // We want to send one last event that will also trigger the node + if(isInspectingNodes && focusedTreeNode) { + sendOnTreeNodeFocusedEvent(focusedTreeNode, true); + } + isInspectingNodes = false; } @@ -215,7 +223,7 @@ enableScreenshotCapture = false; if (isInspectingNodes) { - lastStoreNodesResponse = odc.storeNodeReferences({ + lastStoreNodesResponse = await odc.storeNodeReferences({ includeNodeCountInfo: true, includeArrayGridChildren: true, includeBoundingRectInfo: true @@ -379,10 +387,13 @@ height: {focusedTreeNode.sceneRect.height}
{/if} + + {#if screenshotUrl} Screenshot from Roku device + {/if}
{:else} diff --git a/webviews/src/views/SceneGraphInspectorView/Branch.svelte b/webviews/src/views/SceneGraphInspectorView/Branch.svelte index 4e97375e..6bbf8f71 100644 --- a/webviews/src/views/SceneGraphInspectorView/Branch.svelte +++ b/webviews/src/views/SceneGraphInspectorView/Branch.svelte @@ -1,15 +1,15 @@ -
+
{#if showSettingsPage} {/if} @@ -245,7 +298,7 @@
{:else} -