Skip to content

Commit dcfac99

Browse files
authored
Integrate DTS emulator with workspace view (#4405)
* Scaffold BDP. Signed-off-by: Phillip Hoff <[email protected]> * Refactor type hierarchy. Signed-off-by: Phillip Hoff <[email protected]> * Sketch retrieval of task hubs. Signed-off-by: Phillip Hoff <[email protected]> * Update task hub icon. Signed-off-by: Phillip Hoff <[email protected]> * Enable "open in portal" command for task hubs. Signed-off-by: Phillip Hoff <[email protected]> * Scaffold "open in dashboard" command. Signed-off-by: Phillip Hoff <[email protected]> * Sketch "open in dashboard" implementation. Signed-off-by: Phillip Hoff <[email protected]> * Move DTS management to separate client type. Signed-off-by: Phillip Hoff <[email protected]> * Support viewing task hub properties. Signed-off-by: Phillip Hoff <[email protected]> * Split apart types. Signed-off-by: Phillip Hoff <[email protected]> * Add file headers. Signed-off-by: Phillip Hoff <[email protected]> * Consolidate client logic and add localizable strings. Signed-off-by: Phillip Hoff <[email protected]> * Scaffold creation of task hub. Signed-off-by: Phillip Hoff <[email protected]> * Sketch creation of schedulers. Signed-off-by: Phillip Hoff <[email protected]> * Expose DTS creation from common new menu. Signed-off-by: Phillip Hoff <[email protected]> * Sketch deletion of task hubs. Signed-off-by: Phillip Hoff <[email protected]> * Sketch deletion of schedulers. Signed-off-by: Phillip Hoff <[email protected]> * Sketch refreshing models post-creation. Signed-off-by: Phillip Hoff <[email protected]> * Add tree refresh to remainder of DTS commands. Signed-off-by: Phillip Hoff <[email protected]> * Provide extended schduler properties. Signed-off-by: Phillip Hoff <[email protected]> * Add provisioning state when not "normal". Signed-off-by: Phillip Hoff <[email protected]> * Move creation command to top of context menu. Signed-off-by: Phillip Hoff <[email protected]> * Add copy scheduler endpoint command. Signed-off-by: Phillip Hoff <[email protected]> * Sketch copy connections string command. Signed-off-by: Phillip Hoff <[email protected]> * Add task hub selection for connection string. Signed-off-by: Phillip Hoff <[email protected]> * Add async waits. Signed-off-by: Phillip Hoff <[email protected]> * Wrap deletion in an activity. Signed-off-by: Phillip Hoff <[email protected]> * Add some robustness to API call failures. Signed-off-by: Phillip Hoff <[email protected]> * Tweak strings for task hub selection. Signed-off-by: Phillip Hoff <[email protected]> * Wrap task hub creation with activity. Signed-off-by: Phillip Hoff <[email protected]> * Wrap task hub deletion with activity. Signed-off-by: Phillip Hoff <[email protected]> * Add retry for task hub retrieval. Signed-off-by: Phillip Hoff <[email protected]> * Scaffold DTS emulators workspace tree. Signed-off-by: Phillip Hoff <[email protected]> * Sketch display of running DTS emulators. Signed-off-by: Phillip Hoff <[email protected]> * Scaffold start/stop emulator commands. Signed-off-by: Phillip Hoff <[email protected]> * Implement stop emulator command. Signed-off-by: Phillip Hoff <[email protected]> * Implement start emulator command. Signed-off-by: Phillip Hoff <[email protected]> * Add open dashboard for emulator task hub. Signed-off-by: Phillip Hoff <[email protected]> * Hide DTS commands from palette. Signed-off-by: Phillip Hoff <[email protected]> * Add verify providers step to scheduler creation. Signed-off-by: Phillip Hoff <[email protected]> * Un-hide create scheduler command. Signed-off-by: Phillip Hoff <[email protected]> * Sketch DTS setting. Signed-off-by: Phillip Hoff <[email protected]> * Refactor DTS preview setting name. Signed-off-by: Phillip Hoff <[email protected]> * Add preview features enabled check during create. Signed-off-by: Phillip Hoff <[email protected]> * Stop local emulators on shutdown. Signed-off-by: Phillip Hoff <[email protected]> * Add copy endpoint command to emulator items. Signed-off-by: Phillip Hoff <[email protected]> * Add copy connection string for emulators. Signed-off-by: Phillip Hoff <[email protected]> * Move emulator image details/defaults to configuration. Signed-off-by: Phillip Hoff <[email protected]> * Exclude stopped/paused emulator containers. Signed-off-by: Phillip Hoff <[email protected]> * Tweak emulator shutdown. Signed-off-by: Phillip Hoff <[email protected]> * Hide emulator commands from palette. Signed-off-by: Phillip Hoff <[email protected]> * Add missing headers. Signed-off-by: Phillip Hoff <[email protected]> * Improve container command error handling. Signed-off-by: Phillip Hoff <[email protected]> * Auto-expand when emulators are running. Signed-off-by: Phillip Hoff <[email protected]> * Make primary commands more prominent. * Fixup bad merge. * Updates per PR feedback. * More updates per PR feedback. --------- Signed-off-by: Phillip Hoff <[email protected]>
1 parent 9656036 commit dcfac99

26 files changed

+751
-54
lines changed

package-lock.json

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@
5858
"branches": [
5959
{
6060
"type": "func"
61+
},
62+
{
63+
"type": "DurableTaskSchedulerEmulator"
6164
}
6265
],
6366
"resources": true
@@ -407,6 +410,11 @@
407410
"title": "%azureFunctions.enableSystemIdentity%",
408411
"category": "Azure Functions"
409412
},
413+
{
414+
"command": "azureFunctions.durableTaskScheduler.copyEmulatorConnectionString",
415+
"title": "%azureFunctions.durableTaskScheduler.copyEmulatorConnectionString%",
416+
"category": "Azure Functions"
417+
},
410418
{
411419
"command": "azureFunctions.durableTaskScheduler.copySchedulerConnectionString",
412420
"title": "%azureFunctions.durableTaskScheduler.copySchedulerConnectionString%",
@@ -440,7 +448,20 @@
440448
{
441449
"command": "azureFunctions.durableTaskScheduler.openTaskHubDashboard",
442450
"title": "%azureFunctions.durableTaskScheduler.openTaskHubDashboard%",
443-
"category": "Azure Functions"
451+
"category": "Azure Functions",
452+
"icon": "$(dashboard)"
453+
},
454+
{
455+
"command": "azureFunctions.durableTaskScheduler.startEmulator",
456+
"title": "%azureFunctions.durableTaskScheduler.startEmulator%",
457+
"category": "Azure Functions",
458+
"icon": "$(debug-start)"
459+
},
460+
{
461+
"command": "azureFunctions.durableTaskScheduler.stopEmulator",
462+
"title": "%azureFunctions.durableTaskScheduler.stopEmulator%",
463+
"category": "Azure Functions",
464+
"icon": "$(debug-stop)"
444465
}
445466
],
446467
"submenus": [
@@ -765,14 +786,19 @@
765786
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /userAssignedIdentity/",
766787
"group": "1@1"
767788
},
789+
{
790+
"command": "azureFunctions.durableTaskScheduler.copyEmulatorConnectionString",
791+
"when": "view == azureWorkspace && viewItem =~ /azFunc.dts.emulatorInstance/",
792+
"group": "3@1"
793+
},
768794
{
769795
"command": "azureFunctions.durableTaskScheduler.copySchedulerConnectionString",
770796
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /azFunc.dts.scheduler/",
771797
"group": "3@1"
772798
},
773799
{
774800
"command": "azureFunctions.durableTaskScheduler.copySchedulerEndpoint",
775-
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /azFunc.dts.scheduler/",
801+
"when": "view =~ /(azureResourceGroups|azureWorkspace|azureFocusView)/ && viewItem =~ /azFunc.dts.schedulerEndpoint/",
776802
"group": "3@2"
777803
},
778804
{
@@ -797,8 +823,33 @@
797823
},
798824
{
799825
"command": "azureFunctions.durableTaskScheduler.openTaskHubDashboard",
800-
"when": "view =~ /(azureResourceGroups|azureFocusView)/ && viewItem =~ /azFunc.dts.taskHub/",
826+
"when": "view =~ /(azureResourceGroups|azureWorkspace|azureFocusView)/ && viewItem =~ /azFunc.dts.taskHubDashboard/",
827+
"group": "1@1"
828+
},
829+
{
830+
"command": "azureFunctions.durableTaskScheduler.openTaskHubDashboard",
831+
"when": "view =~ /(azureResourceGroups|azureWorkspace|azureFocusView)/ && viewItem =~ /azFunc.dts.taskHubDashboard/",
832+
"group": "inline"
833+
},
834+
{
835+
"command": "azureFunctions.durableTaskScheduler.startEmulator",
836+
"when": "view == azureWorkspace && viewItem =~ /azFunc.dts.emulators/",
837+
"group": "1@1"
838+
},
839+
{
840+
"command": "azureFunctions.durableTaskScheduler.startEmulator",
841+
"when": "view == azureWorkspace && viewItem =~ /azFunc.dts.emulators/",
842+
"group": "inline"
843+
},
844+
{
845+
"command": "azureFunctions.durableTaskScheduler.stopEmulator",
846+
"when": "view == azureWorkspace && viewItem =~ /azFunc.dts.emulatorInstance/",
801847
"group": "1@1"
848+
},
849+
{
850+
"command": "azureFunctions.durableTaskScheduler.stopEmulator",
851+
"when": "view == azureWorkspace && viewItem =~ /azFunc.dts.emulatorInstance/",
852+
"group": "inline"
802853
}
803854
],
804855
"explorer/context": [
@@ -852,6 +903,10 @@
852903
"command": "azureFunctions.viewProperties",
853904
"when": "never"
854905
},
906+
{
907+
"command": "azureFunctions.durableTaskScheduler.copyEmulatorConnectionString",
908+
"when": "never"
909+
},
855910
{
856911
"command": "azureFunctions.durableTaskScheduler.copySchedulerConnectionString",
857912
"when": "never"
@@ -880,6 +935,10 @@
880935
"command": "azureFunctions.durableTaskScheduler.openTaskHubDashboard",
881936
"when": "never"
882937
},
938+
{
939+
"command": "azureFunctions.durableTaskScheduler.stopEmulator",
940+
"when": "never"
941+
},
883942
{
884943
"command": "azureFunctions.unassignManagedIdentity",
885944
"when": "never"
@@ -997,6 +1056,21 @@
9971056
"type": "boolean",
9981057
"default": false,
9991058
"description": "%azureFunctions.durableTaskScheduler.enablePreviewFeatures%"
1059+
},
1060+
"azureFunctions.durableTaskScheduler.emulatorRegistry": {
1061+
"type": "string",
1062+
"description": "%azureFunctions.durableTaskScheduler.emulatorRegistry%",
1063+
"default": "mcr.microsoft.com"
1064+
},
1065+
"azureFunctions.durableTaskScheduler.emulatorImage": {
1066+
"type": "string",
1067+
"description": "%azureFunctions.durableTaskScheduler.emulatorImage%",
1068+
"default": "dts/dts-emulator"
1069+
},
1070+
"azureFunctions.durableTaskScheduler.emulatorTag": {
1071+
"type": "string",
1072+
"description": "%azureFunctions.durableTaskScheduler.emulatorTag%",
1073+
"default": "latest"
10001074
}
10011075
}
10021076
},
@@ -1390,6 +1464,7 @@
13901464
"vinyl-buffer": "^1.0.1",
13911465
"vinyl-source-stream": "^2.0.0",
13921466
"vscode-azurekudu": "^0.2.0",
1467+
"vscode-jsonrpc": "^8.2.1",
13931468
"webpack": "^5.96.1",
13941469
"webpack-cli": "^4.6.0"
13951470
},
@@ -1410,6 +1485,7 @@
14101485
"@microsoft/vscode-azext-azureutils": "^3.3.3",
14111486
"@microsoft/vscode-azext-utils": "^3.1.1",
14121487
"@microsoft/vscode-azureresources-api": "^2.0.4",
1488+
"@microsoft/vscode-container-client": "^0.1.2",
14131489
"cross-fetch": "^4.0.0",
14141490
"escape-string-regexp": "^4.0.0",
14151491
"extract-zip": "^2.0.1",

package.nls.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
"azureFunctions.walkthrough.functionsStart.scenarios.description": "Learn how you can use Azure Functions to build event-driven systems.\n\nIf you're just getting started with Azure Functions, you can [learn about the anatomy of an Azure Functions application](https://aka.ms/functions-getstarted-devguide).",
125125
"azureFunctions.walkthrough.functionsStart.scenarios.title": "Explore common scenarios",
126126
"azureFunctions.walkthrough.functionsStart.title": "Get Started with Azure Functions",
127+
"azureFunctions.durableTaskScheduler.copyEmulatorConnectionString": "Copy Connection String",
127128
"azureFunctions.durableTaskScheduler.copySchedulerConnectionString": "Copy Connection String",
128129
"azureFunctions.durableTaskScheduler.copySchedulerEndpoint": "Copy Endpoint",
129130
"azureFunctions.durableTaskScheduler.createScheduler": "Create Durable Task Scheduler...",
@@ -132,5 +133,10 @@
132133
"azureFunctions.durableTaskScheduler.deleteScheduler": "Delete Scheduler...",
133134
"azureFunctions.durableTaskScheduler.deleteTaskHub": "Delete Task Hub...",
134135
"azureFunctions.durableTaskScheduler.openTaskHubDashboard": "Open in Dashboard",
135-
"azureFunctions.durableTaskScheduler.enablePreviewFeatures": "Enable Durable Task Scheduler preview features"
136+
"azureFunctions.durableTaskScheduler.startEmulator": "Start Durable Task Emulator",
137+
"azureFunctions.durableTaskScheduler.stopEmulator": "Stop Emulator",
138+
"azureFunctions.durableTaskScheduler.enablePreviewFeatures": "Enable Durable Task Scheduler preview features",
139+
"azureFunctions.durableTaskScheduler.emulatorRegistry": "The registry of the Durable Task Scheduler emulator image.",
140+
"azureFunctions.durableTaskScheduler.emulatorImage": "The name of the Durable Task Scheduler emulator image.",
141+
"azureFunctions.durableTaskScheduler.emulatorTag": "The tag of the Durable Task Scheduler emulator image."
136142
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type IActionContext } from "@microsoft/vscode-azext-utils";
7+
import { localize } from "../../localize";
8+
import { ext } from "../../extensionVariables";
9+
import { env, QuickPickItemKind, type QuickPickItem } from "vscode";
10+
import { type DurableTaskSchedulerEmulatorWorkspaceResourceModel } from "../../tree/durableTaskScheduler/DurableTaskSchedulerEmulatorWorkspaceResourceModel";
11+
12+
export function copyEmulatorConnectionStringCommandFactory() {
13+
return async (actionContext: IActionContext, scheduler: DurableTaskSchedulerEmulatorWorkspaceResourceModel | undefined): Promise<void> => {
14+
if (!scheduler) {
15+
throw new Error(localize('noSchedulerSelectedErrorMessage', 'No scheduler was selected.'));
16+
}
17+
18+
const { endpointUrl } = scheduler;
19+
20+
let connectionString = `Endpoint=${endpointUrl};Authentication=None`;
21+
22+
const taskHubs = scheduler.taskHubs;
23+
24+
if (taskHubs.length > 0) {
25+
26+
const noTaskHubItem: QuickPickItem = {
27+
detail: localize('noTaskHubDetail', 'Do not connect to a specific task hub.'),
28+
label: localize('noTaskHubLabel', 'None')
29+
}
30+
31+
const taskHubItems: QuickPickItem[] =
32+
taskHubs.map(taskHub => ({ label: taskHub }));
33+
34+
const taskHubResult = await actionContext.ui.showQuickPick(
35+
[
36+
noTaskHubItem,
37+
{
38+
kind: QuickPickItemKind.Separator,
39+
label: localize('taskHubSepratorLabel', 'Task Hubs')
40+
},
41+
...taskHubItems
42+
],
43+
{
44+
canPickMany: false,
45+
placeHolder: localize('taskHubSelectionPlaceholder', 'Select a task hub to connect to')
46+
});
47+
48+
if (taskHubResult && taskHubResult !== noTaskHubItem) {
49+
connectionString += `;TaskHub=${taskHubResult.label}`;
50+
}
51+
}
52+
53+
await env.clipboard.writeText(connectionString);
54+
55+
ext.outputChannel.show();
56+
ext.outputChannel.appendLog(localize('schedulerConnectionStringCopiedMessage', 'Connection string copied to clipboard: {0}', connectionString));
57+
}
58+
}

src/commands/durableTaskScheduler/copySchedulerConnectionString.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,7 @@ export function copySchedulerConnectionStringCommandFactory(schedulerClient: Dur
1616
throw new Error(localize('noSchedulerSelectedErrorMessage', 'No scheduler was selected.'));
1717
}
1818

19-
const schedulerJson = await schedulerClient.getScheduler(
20-
scheduler.subscription,
21-
scheduler.resourceGroup,
22-
scheduler.name);
23-
24-
if (!schedulerJson) {
25-
throw new Error(localize('schedulerNotFoundErrorMessage', 'Scheduler does not exist.'));
26-
}
27-
28-
const { endpoint } = schedulerJson.properties;
19+
const { endpointUrl } = scheduler;
2920

3021
const noAuthentication: QuickPickItem = {
3122
detail: localize('noAuthenticationDetail', 'No credentials will be used.'),
@@ -59,7 +50,7 @@ export function copySchedulerConnectionStringCommandFactory(schedulerClient: Dur
5950
placeHolder: localize('authenticationTypePlaceholder', 'Select the credentials to be used to connect to the scheduler')
6051
});
6152

62-
let connectionString = `Endpoint=${endpoint};Authentication=`
53+
let connectionString = `Endpoint=${endpointUrl};Authentication=`
6354

6455
if (result === noAuthentication) {
6556
connectionString += 'None';

src/commands/durableTaskScheduler/copySchedulerEndpoint.ts

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,22 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { type IActionContext } from "@microsoft/vscode-azext-utils";
7-
import { type DurableTaskSchedulerClient } from "../../tree/durableTaskScheduler/DurableTaskSchedulerClient";
8-
import { type DurableTaskSchedulerResourceModel } from "../../tree/durableTaskScheduler/DurableTaskSchedulerResourceModel";
97
import { localize } from "../../localize";
108
import { ext } from "../../extensionVariables";
119
import { env } from "vscode";
10+
import { type DurableTaskSchedulerEndpointModel } from "../../tree/durableTaskScheduler/DurableTaskSchedulerEndpointModel";
1211

13-
export function copySchedulerEndpointCommandFactory(schedulerClient: DurableTaskSchedulerClient) {
14-
return async (_: IActionContext, scheduler: DurableTaskSchedulerResourceModel | undefined): Promise<void> => {
12+
export function copySchedulerEndpointCommandFactory() {
13+
return async (_: IActionContext, scheduler: DurableTaskSchedulerEndpointModel | undefined): Promise<void> => {
1514
if (!scheduler) {
1615
throw new Error(localize('noSchedulerSelectedErrorMessage', 'No scheduler was selected.'));
1716
}
1817

19-
const schedulerJson = await schedulerClient.getScheduler(
20-
scheduler.subscription,
21-
scheduler.resourceGroup,
22-
scheduler.name);
18+
const { endpointUrl } = scheduler;
2319

24-
if (!schedulerJson) {
25-
throw new Error(localize('schedulerNotFoundErrorMessage', 'Scheduler does not exist.'));
26-
}
27-
28-
const { endpoint } = schedulerJson.properties;
29-
30-
await env.clipboard.writeText(endpoint);
20+
await env.clipboard.writeText(endpointUrl.toString());
3121

3222
ext.outputChannel.show();
33-
ext.outputChannel.appendLog(localize('schedulerEndpointCopiedMessage', 'Endpoint copied to clipboard: {0}', endpoint));
23+
ext.outputChannel.appendLog(localize('schedulerEndpointCopiedMessage', 'Endpoint copied to clipboard: {0}', endpointUrl.toString()));
3424
}
3525
}

src/commands/durableTaskScheduler/openTaskHubDashboard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { openUrl, type IActionContext } from "@microsoft/vscode-azext-utils";
7-
import { type DurableTaskHubResourceModel } from "../../tree/durableTaskScheduler/DurableTaskHubResourceModel";
87
import { localize } from '../../localize';
8+
import { type DurableTaskSchedulerDashboardModel } from "../../tree/durableTaskScheduler/DurableTaskSchedulerDashboardModel";
99

10-
export async function openTaskHubDashboard(_: IActionContext, taskHub: DurableTaskHubResourceModel | undefined): Promise<void> {
10+
export async function openTaskHubDashboard(_: IActionContext, taskHub: DurableTaskSchedulerDashboardModel | undefined): Promise<void> {
1111
if (!taskHub) {
1212
throw new Error(localize('noTaskHubSelectedErrorMessage', 'No task hub was selected.'));
1313
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { type IActionContext } from "@microsoft/vscode-azext-utils";
7+
import { type DurableTaskSchedulerEmulatorClient } from "../../tree/durableTaskScheduler/DurableTaskSchedulerEmulatorClient";
8+
9+
export function startEmulatorCommandFactory(emulatorClient: DurableTaskSchedulerEmulatorClient) {
10+
return async (_: IActionContext) => {
11+
await emulatorClient.startEmulator();
12+
};
13+
}

0 commit comments

Comments
 (0)