Skip to content

Commit

Permalink
Add app dropdown menu for ECP registry link (#514)
Browse files Browse the repository at this point in the history
* Duplicate code

* add dropdown menu to pick which app to use

* Make requested changes

* Realized I no longer need to parse http response for xml

* undo changes to util input box

* No longer need socket in this file

* new icon, add app picker divider, consolidate code

* fix lint issues

---------

Co-authored-by: Bronley Plumb <[email protected]>
  • Loading branch information
MilapNaik and TwitchBronBron authored Nov 16, 2023
1 parent 728b8d9 commit 42b2858
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 12 deletions.
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"@types/semver": "^7.1.0",
"@types/sinon": "7.0.6",
"@types/vscode": "^1.53.0",
"@types/xml2js": "^0.4.14",
"@types/yargs": "^17.0.10",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
Expand Down Expand Up @@ -2725,6 +2726,12 @@
"command": "extension.brightscript.rokuRegistry.exportRegistry",
"title": "Export Registry",
"category": "BrighterScript",
"icon": "$(browser)"
},
{
"command": "extension.brightscript.openRegistryInBrowser",
"title": "Open device registry in a browser",
"category": "BrighterScript",
"icon": "$(arrow-up)"
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/BrightScriptCommands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('BrightScriptFileUtils ', () => {
let languagesMock;

beforeEach(() => {
commands = new BrightScriptCommands({} as any, {} as any, {} as any, {} as any);
commands = new BrightScriptCommands({} as any, {} as any, {} as any, {} as any, {} as any);
commandsMock = sinon.mock(commands);
languagesMock = sinon.mock(vscode.languages);
});
Expand Down
52 changes: 51 additions & 1 deletion src/BrightScriptCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ import { util as rokuDebugUtil } from 'roku-debug/dist/util';
import type { RemoteControlManager, RemoteControlModeInitiator } from './managers/RemoteControlManager';
import type { WhatsNewManager } from './managers/WhatsNewManager';
import type { ActiveDeviceManager } from './ActiveDeviceManager';
import * as xml2js from 'xml2js';
import { firstBy } from 'thenby';
import type { UserInputManager } from './managers/UserInputManager';

export class BrightScriptCommands {

constructor(
private remoteControlManager: RemoteControlManager,
private whatsNewManager: WhatsNewManager,
private context: vscode.ExtensionContext,
private activeDeviceManager: ActiveDeviceManager
private activeDeviceManager: ActiveDeviceManager,
private userInputManager: UserInputManager
) {
this.fileUtils = new BrightScriptFileUtils();
}
Expand Down Expand Up @@ -263,6 +267,52 @@ export class BrightScriptCommands {
}
});

this.registerCommand('openRegistryInBrowser', async (host: string) => {
if (!host) {
host = await this.userInputManager.promptForHost();
}

let responseText = await util.spinAsync('Fetching app list', async () => {
return (await util.httpGet(`http://${host}:8060/query/apps`, { timeout: 4_000 })).body as string;
});

const parsed = await xml2js.parseStringPromise(responseText);

//convert the items to QuickPick items
const items: Array<vscode.QuickPickItem & { appId?: string }> = parsed.apps.app.map((appData: any) => {
return {
label: appData._,
detail: `ID: ${appData.$.id}`,
description: `${appData.$.version}`,
appId: `${appData.$.id}`
} as vscode.QuickPickItem;
//sort the items alphabetically
}).sort(firstBy('label'));

//move the dev app to the top (and add a label/section to differentiate it)
const devApp = items.find(x => x.appId === 'dev');
if (devApp) {
items.splice(items.indexOf(devApp), 1);
items.unshift(
{ kind: vscode.QuickPickItemKind.Separator, label: 'dev' },
devApp,
{ kind: vscode.QuickPickItemKind.Separator, label: ' ' }
);
}

const selectedApp: typeof items[0] = await vscode.window.showQuickPick(items, { placeHolder: 'Which app would you like to see the registry for?' });

if (selectedApp) {
const appId = selectedApp.appId;
let url = `http://${host}:8060/query/registry/${appId}`;
try {
await vscode.env.openExternal(vscode.Uri.parse(url));
} catch (error) {
await vscode.window.showErrorMessage(`Tried to open url but failed: ${url}`);
}
}
});

this.registerCommand('showReleaseNotes', () => {
this.whatsNewManager.showReleaseNotes();
});
Expand Down
3 changes: 2 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ export class Extension {
this.remoteControlManager,
this.whatsNewManager,
context,
activeDeviceManager
activeDeviceManager,
userInputManager
);

this.rtaManager = new RtaManager();
Expand Down
2 changes: 1 addition & 1 deletion src/managers/WebviewViewProviderManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('WebviewViewProviderManager', () => {
const config = {} as BrightScriptLaunchConfiguration;
let webviewViewProviderManager: WebviewViewProviderManager;
let rtaManager: RtaManager;
const brightScriptCommands = new BrightScriptCommands({} as any, {} as any, {} as any, {} as any);
const brightScriptCommands = new BrightScriptCommands({} as any, {} as any, {} as any, {} as any, {} as any);

before(() => {
context = {
Expand Down
38 changes: 38 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { Cache } from 'brighterscript/dist/Cache';
import undent from 'undent';
import { EXTENSION_ID, ROKU_DEBUG_VERSION } from './constants';
import type { DeviceInfo } from 'roku-deploy';
import * as r from 'postman-request';
import type { Response } from 'request';
import type * as requestType from 'request';
const request = r as typeof requestType;

class Util {
public async readDir(dirPath: string) {
Expand Down Expand Up @@ -385,6 +389,17 @@ class Util {
return text?.toString().replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

/**
* Do an http GET request
*/
public httpGet(url: string, options?: requestType.CoreOptions) {
return new Promise<Response>((resolve, reject) => {
request.get(url, options, (err, response) => {
return err ? reject(err) : resolve(response);
});
});
}

public async openIssueReporter(options: { title?: string; body?: string; deviceInfo?: DeviceInfo }) {
if (!options.body) {
options.body = undent`
Expand All @@ -409,6 +424,29 @@ class Util {
issueBody: options.body
});
}

public createStatusbarSpinner(message: string) {
const statusbarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 9_999_999);
statusbarItem.text = `$(sync~spin) ${message}`;
statusbarItem.show();
return statusbarItem;
}

/**
* Show a statusbar spinner that is hidden once the callback resolves
* @param message the message that should be shown in the statusbar spinner
* @param callback the function to run, that when completed will hide the spinner
* @returns
*/
public async spinAsync<T>(message: string, callback: () => Promise<T>) {
const spinner = this.createStatusbarSpinner(message);
try {
const result = await callback();
return result;
} finally {
spinner.dispose();
}
}
}

const util = new Util();
Expand Down
11 changes: 3 additions & 8 deletions src/viewProviders/OnlineDevicesViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,15 @@ export class OnlineDevicesViewProvider implements vscode.TreeDataProvider<vscode
// TODO: add ECP system hooks here in the future (like registry call, etc...)
result.unshift(
this.createDeviceInfoTreeItem({
label: '🔗 View Registry',
label: '📋 View Registry',
parent: element,
collapsibleState: vscode.TreeItemCollapsibleState.None,
tooltip: 'View the ECP Registry',
description: device.ip,
command: {
command: 'extension.brightscript.openUrl',
command: 'extension.brightscript.openRegistryInBrowser',
title: 'Open',
arguments: [`http://${device.ip}:8060/query/registry/dev`]
arguments: [device.ip]
}
})
);
Expand All @@ -170,11 +170,6 @@ export class OnlineDevicesViewProvider implements vscode.TreeDataProvider<vscode
})
);


if (semver.satisfies(element.details['software-version'], '>=11')) {
// TODO: add ECP system hooks here in the future (like registry call, etc...)
}

// Return the device details
return result;
}
Expand Down

0 comments on commit 42b2858

Please sign in to comment.