diff --git a/package.json b/package.json
index 4ff684ff..f194994c 100644
--- a/package.json
+++ b/package.json
@@ -570,6 +570,11 @@
{
"command": "azure-iot-toolkit.startMonitorIoTHubMessageWithAbbreviation",
"when": "view == iotHubDevices && viewItem == events"
+ },
+ {
+ "command": "azure-iot-toolkit.refresh",
+ "when": "view == iotHubDevices && viewItem == interfaces-label",
+ "group": "inline"
}
],
"editor/context": [
diff --git a/resources/interface.svg b/resources/interface.svg
new file mode 100644
index 00000000..49381c1f
--- /dev/null
+++ b/resources/interface.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/Model/InterfaceItem.ts b/src/Model/InterfaceItem.ts
new file mode 100644
index 00000000..1ffe0c51
--- /dev/null
+++ b/src/Model/InterfaceItem.ts
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+import { TreeItem } from "vscode";
+
+export class InterfaceItem extends TreeItem {
+ constructor(name: string, public readonly iconPath: string) {
+ super(name);
+ this.contextValue = "interface";
+ }
+}
diff --git a/src/Nodes/DeviceNode.ts b/src/Nodes/DeviceNode.ts
index 4bf98d6d..9a37500c 100644
--- a/src/Nodes/DeviceNode.ts
+++ b/src/Nodes/DeviceNode.ts
@@ -7,6 +7,7 @@ import { DeviceItem } from "../Model/DeviceItem";
import { TelemetryClient } from "../telemetryClient";
import { DistributedTracingLabelNode } from "./DistributedTracingLabelNode";
import { INode } from "./INode";
+import { InterfaceLabelNode } from "./InterfaceLabelNode";
import { ModuleLabelNode } from "./ModuleLabelNode";
export class DeviceNode implements INode {
@@ -24,6 +25,7 @@ export class DeviceNode implements INode {
public async getChildren(context: vscode.ExtensionContext, iotHubConnectionString: string): Promise {
let nodeList: INode[] = [];
nodeList.push(new ModuleLabelNode(this));
+ nodeList.push(new InterfaceLabelNode(this));
if (this.deviceItem.contextValue === "device" && iotHubConnectionString.toLowerCase().indexOf("azure-devices.cn;") < 0) {
nodeList.push(new DistributedTracingLabelNode(this));
}
diff --git a/src/Nodes/InterfaceLabelNode.ts b/src/Nodes/InterfaceLabelNode.ts
new file mode 100644
index 00000000..541e777c
--- /dev/null
+++ b/src/Nodes/InterfaceLabelNode.ts
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+import axios from "axios";
+import * as path from "path";
+import * as vscode from "vscode";
+import { Constants } from "../constants";
+import { TelemetryClient } from "../telemetryClient";
+import { Utility } from "../utility";
+import { DeviceNode } from "./DeviceNode";
+import { InfoNode } from "./InfoNode";
+import { INode } from "./INode";
+import { InterfaceNode } from "./InterfaceNode";
+
+export class InterfaceLabelNode implements INode {
+ constructor(public deviceNode: DeviceNode) {
+ }
+
+ public getTreeItem(): vscode.TreeItem {
+ return {
+ label: "Interfaces",
+ collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
+ contextValue: "interfaces-label",
+ };
+ }
+
+ public async getChildren(context: vscode.ExtensionContext, iotHubConnectionString: string): Promise {
+ TelemetryClient.sendEvent(Constants.IoTHubAILoadInterfacesTreeStartEvent);
+
+ try {
+ const interfaces = (await axios.request(Utility.generateIoTHubAxiosRequestConfig(
+ iotHubConnectionString,
+ `/digitalTwins/${this.deviceNode.deviceId}/interfaces?api-version=${Constants.IoTHubApiVersion}`,
+ "get",
+ ))).data;
+ TelemetryClient.sendEvent(Constants.IoTHubAILoadInterfacesTreeDoneEvent, { Result: "Success" });
+ if (!interfaces || !interfaces.interfaces || Object.keys(interfaces.interfaces).length === 0) {
+ return [new InfoNode("No Interfaces")];
+ }
+ return Object.keys(interfaces.interfaces).map((name) => new InterfaceNode(name, context.asAbsolutePath(path.join("resources", `interface.svg`))));
+ } catch (err) {
+ TelemetryClient.sendEvent(Constants.IoTHubAILoadInterfacesTreeDoneEvent, { Result: "Fail", Message: err.message });
+ return Utility.getErrorMessageTreeItems("interfaces", err.message);
+ }
+ }
+}
diff --git a/src/Nodes/InterfaceNode.ts b/src/Nodes/InterfaceNode.ts
new file mode 100644
index 00000000..44160b79
--- /dev/null
+++ b/src/Nodes/InterfaceNode.ts
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license.
+
+import * as vscode from "vscode";
+import { InterfaceItem } from "../Model/InterfaceItem";
+import { INode } from "./INode";
+
+export class InterfaceNode implements INode {
+ constructor(private name: string, private iconPath: string) {
+ }
+
+ public getTreeItem(): vscode.TreeItem {
+ return new InterfaceItem(this.name, this.iconPath);
+ }
+
+ public getChildren(): INode[] {
+ return [];
+ }
+}
diff --git a/src/constants.ts b/src/constants.ts
index 3e408e01..874e9214 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -123,6 +123,8 @@ export class Constants {
public static CREATE_OPTIONS_MAX_CHUNKS = 8;
public static StateKeySubsID = "subscriptionId";
public static StateKeyIoTHubID = "iothubid";
+ public static IoTHubAILoadInterfacesTreeStartEvent = "AZ.LoadInterfacesTree.Start";
+ public static IoTHubAILoadInterfacesTreeDoneEvent = "AZ.LoadInterfacesTree.Done";
public static DeleteLabel = "Delete";
public static DeleteMessage = "Are you sure you want to delete"; public static readonly DISTRIBUTED_TWIN_NAME: string = "azureiot*com^dtracing^1";
@@ -138,7 +140,7 @@ export class Constants {
public static ShowIoTHubInfoKey = "showIoTHubInfo";
public static ShowConnectionStringInputBoxKey = "showConnectionStringInputBox";
- public static IoTHubApiVersion = "2018-06-30";
+ public static IoTHubApiVersion = "2019-07-01-preview";
public static CodeTemplates = {
[TemplateLanguage.CSharp]: {
diff --git a/src/utility.ts b/src/utility.ts
index 224a53ae..141051ae 100644
--- a/src/utility.ts
+++ b/src/utility.ts
@@ -20,6 +20,7 @@ import { INode } from "./Nodes/INode";
import { TelemetryClient } from "./telemetryClient";
import iothub = require("azure-iothub");
import { EventData } from "@azure/event-hubs";
+import { AxiosRequestConfig } from "axios";
import { IotHubDescription } from "azure-arm-iothub/lib/models";
import { AzureAccount } from "./azure-account.api";
import { CredentialStore } from "./credentialStore";
@@ -423,6 +424,18 @@ export class Utility {
await Constants.ExtensionContext.globalState.update(Constants.StateKeyIoTHubID, "");
}
+ public static generateIoTHubAxiosRequestConfig(iotHubConnectionString: string, url: string, method: string, data?: any): AxiosRequestConfig {
+ return {
+ url,
+ method,
+ baseURL: `https://${Utility.getHostName(iotHubConnectionString)}`,
+ headers: {
+ Authorization: Utility.generateSasTokenForService(iotHubConnectionString),
+ },
+ data,
+ };
+ }
+
private static tryGetStringFromCharCode(source) {
if (source instanceof Uint8Array) {
try {