From fba4c241811e944852153e0ac9ccf51a7a12d7eb Mon Sep 17 00:00:00 2001 From: emily-shen <69125074+emily-shen@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:56:42 +0000 Subject: [PATCH 1/5] add 'add binding' command --- .../package.json | 12 +- .../resources/icons/d1.svg | 1 + .../resources/icons/kv.svg | 1 + .../resources/icons/r2.svg | 1 + .../src/add-binding.ts | 361 ++++++++++++++++++ .../src/bindings.ts | 19 +- .../src/extension.ts | 8 +- .../src/wrangler.ts | 1 + 8 files changed, 394 insertions(+), 10 deletions(-) create mode 100644 packages/cloudflare-workers-bindings-extension/resources/icons/d1.svg create mode 100644 packages/cloudflare-workers-bindings-extension/resources/icons/kv.svg create mode 100644 packages/cloudflare-workers-bindings-extension/resources/icons/r2.svg create mode 100644 packages/cloudflare-workers-bindings-extension/src/add-binding.ts diff --git a/packages/cloudflare-workers-bindings-extension/package.json b/packages/cloudflare-workers-bindings-extension/package.json index 94b1b21f76c8..ac5ab7d280d0 100644 --- a/packages/cloudflare-workers-bindings-extension/package.json +++ b/packages/cloudflare-workers-bindings-extension/package.json @@ -31,6 +31,11 @@ "command": "cloudflare-workers-bindings.refresh", "title": "Cloudflare Workers: Refresh bindings", "icon": "$(refresh)" + }, + { + "command": "cloudflare-workers-bindings.addEntry", + "title": "Cloudflare Workers: Add binding", + "icon": "$(add)" } ], "menus": { @@ -39,6 +44,11 @@ "command": "cloudflare-workers-bindings.refresh", "when": "view == cloudflare-workers-bindings", "group": "navigation" + }, + { + "command": "cloudflare-workers-bindings.addEntry", + "when": "view == cloudflare-workers-bindings", + "group": "navigation" } ] }, @@ -64,7 +74,7 @@ "viewsWelcome": [ { "view": "cloudflare-workers-bindings", - "contents": "Welcome to Cloudflare Workers! [Learn more](https://workers.cloudflare.com).\n[Refresh Bindings](command:cloudflare-workers-bindings.refresh)" + "contents": "Welcome to Cloudflare Workers! [Learn more](https://workers.cloudflare.com).\n[Add a binding](command:cloudflare-workers-bindings.addEntry)" } ] }, diff --git a/packages/cloudflare-workers-bindings-extension/resources/icons/d1.svg b/packages/cloudflare-workers-bindings-extension/resources/icons/d1.svg new file mode 100644 index 000000000000..e1943befd6f4 --- /dev/null +++ b/packages/cloudflare-workers-bindings-extension/resources/icons/d1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/cloudflare-workers-bindings-extension/resources/icons/kv.svg b/packages/cloudflare-workers-bindings-extension/resources/icons/kv.svg new file mode 100644 index 000000000000..aa5283cba381 --- /dev/null +++ b/packages/cloudflare-workers-bindings-extension/resources/icons/kv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/cloudflare-workers-bindings-extension/resources/icons/r2.svg b/packages/cloudflare-workers-bindings-extension/resources/icons/r2.svg new file mode 100644 index 000000000000..7eb01e06b7cd --- /dev/null +++ b/packages/cloudflare-workers-bindings-extension/resources/icons/r2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts new file mode 100644 index 000000000000..d7900ba30baa --- /dev/null +++ b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts @@ -0,0 +1,361 @@ +import { + Disposable, + env, + ExtensionContext, + QuickInput, + QuickInputButton, + QuickInputButtons, + QuickPickItem, + Uri, + window, + workspace, +} from "vscode"; +import { getConfigUri } from "./bindings"; +import { importWrangler } from "./wrangler"; + +class BindingType implements QuickPickItem { + constructor( + public label: string, + public description?: string, + public detail?: string, + public iconPath?: Uri + ) {} +} +/** + * A multi-step input using window.createQuickPick() and window.createInputBox(). + * + * This first part uses the helper class `MultiStepInput` that wraps the API for the multi-step case. + */ +export async function multiStepInput( + context: ExtensionContext + // rootPath: string +) { + const bindingTypes: BindingType[] = [ + new BindingType( + "KV", + "kv_namespaces", + "Global, low-latency, key-value data storage", + Uri.file(context.asAbsolutePath("resources/icons/kv.svg")) + ), + new BindingType( + "R2", + "r2_buckets", + "Object storage for all your data", + Uri.file(context.asAbsolutePath("resources/icons/r2.svg")) + ), + new BindingType( + "D1", + "d1_databases", + "Serverless SQL databases", + Uri.file(context.asAbsolutePath("resources/icons/d1.svg")) + ), + ]; + + interface State { + title: string; + step: number; + totalSteps: number; + bindingType: BindingType; + name: string; + runtime: QuickPickItem; + id: string; + } + + async function collectInputs() { + const state = {} as Partial; + await MultiStepInput.run((input) => pickResourceGroup(input, state)); + return state as State; + } + + const title = "Add binding"; + + async function pickResourceGroup( + input: MultiStepInput, + state: Partial + ) { + const pick = await input.showQuickPick({ + title, + step: 1, + totalSteps: 2, + placeholder: "Choose a binding type", + items: bindingTypes, + activeItem: + typeof state.bindingType !== "string" ? state.bindingType : undefined, + // shouldResume, + }); + state.bindingType = pick as BindingType; + return (input: MultiStepInput) => inputName(input, state); + } + + async function inputName(input: MultiStepInput, state: Partial) { + // TODO: Remember current value when navigating back. + + let name = await input.showInputBox({ + title, + step: 2, + totalSteps: 2, + value: state.name || "", + prompt: "Choose a binding name", + validate: validateNameIsUnique, + placeholder: `e.g. MY_BINDING`, + // shouldResume, + }); + state.name = name; + return () => addToToml(state); + } + + async function addToToml(state: Partial) { + const configUri = await getConfigUri(); + if (!configUri) { + return null; + } + const workspaceFolder = workspace.getWorkspaceFolder(configUri); + + if (!workspaceFolder) { + return null; + } + + const wrangler = importWrangler(workspaceFolder.uri.fsPath); + + await workspace.openTextDocument(configUri).then((doc) => { + window.showTextDocument(doc); + try { + wrangler.experimental_patchConfig(configUri.path, { + [state.bindingType?.description!]: [{ binding: state.name! }], + }); + window.showInformationMessage(`Created binding '${state.name}'`); + } catch { + window.showErrorMessage( + `Unable to directly add binding to config file. A snippet has been copied to clipboard - please paste this into your config file.` + ); + + const patch = `[[${state.bindingType?.description!}]] +binding = "${state.name}" +`; + + env.clipboard.writeText(patch); + } + }); + } + + async function validateNameIsUnique(name: string) { + // TODO: actually validate uniqueness + return name === "SOME_KV_BINDING" ? "Name not unique" : undefined; + } + + const state = await collectInputs(); +} + +// ------------------------------------------------------- +// Helper code that wraps the API for the multi-step case. +// ------------------------------------------------------- + +class InputFlowAction { + static back = new InputFlowAction(); + static cancel = new InputFlowAction(); + static resume = new InputFlowAction(); +} + +type InputStep = (input: MultiStepInput) => Thenable; + +interface QuickPickParameters { + title: string; + step: number; + totalSteps: number; + items: T[]; + activeItem?: T; + ignoreFocusOut?: boolean; + placeholder: string; + buttons?: QuickInputButton[]; +} + +interface InputBoxParameters { + title: string; + step: number; + totalSteps: number; + value: string; + prompt: string; + validate: (value: string) => Promise; + buttons?: QuickInputButton[]; + ignoreFocusOut?: boolean; + placeholder?: string; + // shouldResume: () => Thenable; +} + +export class MultiStepInput { + static async run(start: InputStep) { + const input = new MultiStepInput(); + return input.stepThrough(start); + } + + private current?: QuickInput; + private steps: InputStep[] = []; + + private async stepThrough(start: InputStep) { + let step: InputStep | void = start; + while (step) { + this.steps.push(step); + if (this.current) { + this.current.enabled = false; + this.current.busy = true; + } + try { + step = await step(this); + } catch (err) { + if (err === InputFlowAction.back) { + this.steps.pop(); + step = this.steps.pop(); + } else if (err === InputFlowAction.resume) { + step = this.steps.pop(); + } else if (err === InputFlowAction.cancel) { + step = undefined; + } else { + throw err; + } + } + } + if (this.current) { + this.current.dispose(); + } + } + + async showQuickPick< + T extends QuickPickItem, + P extends QuickPickParameters, + >({ + title, + step, + totalSteps, + items, + activeItem, + ignoreFocusOut, + placeholder, + buttons, + // shouldResume, + }: P) { + const disposables: Disposable[] = []; + try { + return await new Promise< + T | (P extends { buttons: (infer I)[] } ? I : never) + >((resolve, reject) => { + const input = window.createQuickPick(); + input.title = title; + input.step = step; + input.totalSteps = totalSteps; + input.ignoreFocusOut = ignoreFocusOut ?? false; + input.placeholder = placeholder; + input.items = items; + if (activeItem) { + input.activeItems = [activeItem]; + } + input.buttons = [ + ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), + ...(buttons || []), + ]; + disposables.push( + input.onDidTriggerButton((item) => { + if (item === QuickInputButtons.Back) { + reject(InputFlowAction.back); + } else { + resolve(item); + } + }), + input.onDidChangeSelection((items) => resolve(items[0])) + // input.onDidHide(() => { + // (async () => { + // reject( + // shouldResume && (await shouldResume()) + // ? InputFlowAction.resume + // : InputFlowAction.cancel + // ); + // })().catch(reject); + // }) + ); + if (this.current) { + this.current.dispose(); + } + this.current = input; + this.current.show(); + }); + } finally { + disposables.forEach((d) => d.dispose()); + } + } + + async showInputBox

({ + title, + step, + totalSteps, + value, + prompt, + validate, + buttons, + ignoreFocusOut, + placeholder, + // shouldResume, + }: P) { + const disposables: Disposable[] = []; + try { + return await new Promise< + string | (P extends { buttons: (infer I)[] } ? I : never) + >((resolve, reject) => { + const input = window.createInputBox(); + input.title = title; + input.step = step; + input.totalSteps = totalSteps; + input.value = value || ""; + input.prompt = prompt; + input.ignoreFocusOut = ignoreFocusOut ?? false; + input.placeholder = placeholder; + input.buttons = [ + ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), + ...(buttons || []), + ]; + let validating = validate(""); + disposables.push( + input.onDidTriggerButton((item) => { + if (item === QuickInputButtons.Back) { + reject(InputFlowAction.back); + } else { + resolve(item); + } + }), + input.onDidAccept(async () => { + const value = input.value; + input.enabled = false; + input.busy = true; + if (!(await validate(value))) { + resolve(value); + } + input.enabled = true; + input.busy = false; + }), + input.onDidChangeValue(async (text) => { + const current = validate(text); + validating = current; + const validationMessage = await current; + if (current === validating) { + input.validationMessage = validationMessage; + } + }) + // input.onDidHide(() => { + // (async () => { + // reject( + // shouldResume && (await shouldResume()) + // ? InputFlowAction.resume + // : InputFlowAction.cancel + // ); + // })().catch(reject); + // }) + ); + if (this.current) { + this.current.dispose(); + } + this.current = input; + this.current.show(); + }); + } finally { + disposables.forEach((d) => d.dispose()); + } + } +} diff --git a/packages/cloudflare-workers-bindings-extension/src/bindings.ts b/packages/cloudflare-workers-bindings-extension/src/bindings.ts index 817b39fdebbd..5e4c7f715daf 100644 --- a/packages/cloudflare-workers-bindings-extension/src/bindings.ts +++ b/packages/cloudflare-workers-bindings-extension/src/bindings.ts @@ -200,26 +200,29 @@ export class BindingsProvider implements vscode.TreeDataProvider { // Finds the first wrangler config file in the workspace and parse it export async function getWranglerConfig(): Promise { - const [configUri] = await vscode.workspace.findFiles( - "wrangler.{toml,jsonc,json}", - null, - 1 - ); - + const configUri = await getConfigUri(); if (!configUri) { return null; } - const workspaceFolder = vscode.workspace.getWorkspaceFolder(configUri); if (!workspaceFolder) { return null; } - const wrangler = await importWrangler(workspaceFolder.uri.fsPath); + const wrangler = importWrangler(workspaceFolder.uri.fsPath); const { rawConfig } = wrangler.experimental_readRawConfig({ config: configUri.fsPath, }); return rawConfig; } + +export async function getConfigUri(): Promise { + const [configUri] = await vscode.workspace.findFiles( + "wrangler.{toml,jsonc,json}", + null, + 1 + ); + return configUri; +} diff --git a/packages/cloudflare-workers-bindings-extension/src/extension.ts b/packages/cloudflare-workers-bindings-extension/src/extension.ts index 9da94758ee44..d91a7e71ac4b 100644 --- a/packages/cloudflare-workers-bindings-extension/src/extension.ts +++ b/packages/cloudflare-workers-bindings-extension/src/extension.ts @@ -1,4 +1,5 @@ import * as vscode from "vscode"; +import { multiStepInput } from "./add-binding"; import { BindingsProvider } from "./bindings"; export type Result = { @@ -31,7 +32,12 @@ export async function activate( "cloudflare-workers-bindings.refresh", () => bindingsProvider.refresh() ); - + vscode.commands.registerCommand( + "cloudflare-workers-bindings.addEntry", + async () => { + await multiStepInput(context); + } + ); // Cleanup when the extension is deactivated context.subscriptions.push(bindingsView, watcher, refreshCommand); diff --git a/packages/cloudflare-workers-bindings-extension/src/wrangler.ts b/packages/cloudflare-workers-bindings-extension/src/wrangler.ts index 2e35d08288e2..3f23a1f4e6a9 100644 --- a/packages/cloudflare-workers-bindings-extension/src/wrangler.ts +++ b/packages/cloudflare-workers-bindings-extension/src/wrangler.ts @@ -1,4 +1,5 @@ import * as path from "path"; +import * as vscode from "vscode"; export function importWrangler( workspaceRoot: string From f2c7493f26974ea0ffd4df24240d250ac0ef5119 Mon Sep 17 00:00:00 2001 From: emily-shen <69125074+emily-shen@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:22:37 +0000 Subject: [PATCH 2/5] cleanup --- .../package.json | 6 ++-- .../src/add-binding.ts | 36 ++----------------- .../src/extension.ts | 4 ++- 3 files changed, 8 insertions(+), 38 deletions(-) diff --git a/packages/cloudflare-workers-bindings-extension/package.json b/packages/cloudflare-workers-bindings-extension/package.json index ac5ab7d280d0..1891f9ff2625 100644 --- a/packages/cloudflare-workers-bindings-extension/package.json +++ b/packages/cloudflare-workers-bindings-extension/package.json @@ -33,7 +33,7 @@ "icon": "$(refresh)" }, { - "command": "cloudflare-workers-bindings.addEntry", + "command": "cloudflare-workers-bindings.addBinding", "title": "Cloudflare Workers: Add binding", "icon": "$(add)" } @@ -46,7 +46,7 @@ "group": "navigation" }, { - "command": "cloudflare-workers-bindings.addEntry", + "command": "cloudflare-workers-bindings.addBinding", "when": "view == cloudflare-workers-bindings", "group": "navigation" } @@ -74,7 +74,7 @@ "viewsWelcome": [ { "view": "cloudflare-workers-bindings", - "contents": "Welcome to Cloudflare Workers! [Learn more](https://workers.cloudflare.com).\n[Add a binding](command:cloudflare-workers-bindings.addEntry)" + "contents": "Welcome to Cloudflare Workers! [Learn more](https://workers.cloudflare.com).\n[Add a binding](command:cloudflare-workers-bindings.addBinding)" } ] }, diff --git a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts index d7900ba30baa..450ccdee31e9 100644 --- a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts +++ b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts @@ -21,15 +21,8 @@ class BindingType implements QuickPickItem { public iconPath?: Uri ) {} } -/** - * A multi-step input using window.createQuickPick() and window.createInputBox(). - * - * This first part uses the helper class `MultiStepInput` that wraps the API for the multi-step case. - */ -export async function multiStepInput( - context: ExtensionContext - // rootPath: string -) { + +export async function multiStepInput(context: ExtensionContext) { const bindingTypes: BindingType[] = [ new BindingType( "KV", @@ -81,15 +74,12 @@ export async function multiStepInput( items: bindingTypes, activeItem: typeof state.bindingType !== "string" ? state.bindingType : undefined, - // shouldResume, }); state.bindingType = pick as BindingType; return (input: MultiStepInput) => inputName(input, state); } async function inputName(input: MultiStepInput, state: Partial) { - // TODO: Remember current value when navigating back. - let name = await input.showInputBox({ title, step: 2, @@ -98,7 +88,6 @@ export async function multiStepInput( prompt: "Choose a binding name", validate: validateNameIsUnique, placeholder: `e.g. MY_BINDING`, - // shouldResume, }); state.name = name; return () => addToToml(state); @@ -179,7 +168,6 @@ interface InputBoxParameters { buttons?: QuickInputButton[]; ignoreFocusOut?: boolean; placeholder?: string; - // shouldResume: () => Thenable; } export class MultiStepInput { @@ -231,7 +219,6 @@ export class MultiStepInput { ignoreFocusOut, placeholder, buttons, - // shouldResume, }: P) { const disposables: Disposable[] = []; try { @@ -261,15 +248,6 @@ export class MultiStepInput { } }), input.onDidChangeSelection((items) => resolve(items[0])) - // input.onDidHide(() => { - // (async () => { - // reject( - // shouldResume && (await shouldResume()) - // ? InputFlowAction.resume - // : InputFlowAction.cancel - // ); - // })().catch(reject); - // }) ); if (this.current) { this.current.dispose(); @@ -292,7 +270,6 @@ export class MultiStepInput { buttons, ignoreFocusOut, placeholder, - // shouldResume, }: P) { const disposables: Disposable[] = []; try { @@ -338,15 +315,6 @@ export class MultiStepInput { input.validationMessage = validationMessage; } }) - // input.onDidHide(() => { - // (async () => { - // reject( - // shouldResume && (await shouldResume()) - // ? InputFlowAction.resume - // : InputFlowAction.cancel - // ); - // })().catch(reject); - // }) ); if (this.current) { this.current.dispose(); diff --git a/packages/cloudflare-workers-bindings-extension/src/extension.ts b/packages/cloudflare-workers-bindings-extension/src/extension.ts index d91a7e71ac4b..3ce99f903cfb 100644 --- a/packages/cloudflare-workers-bindings-extension/src/extension.ts +++ b/packages/cloudflare-workers-bindings-extension/src/extension.ts @@ -32,8 +32,10 @@ export async function activate( "cloudflare-workers-bindings.refresh", () => bindingsProvider.refresh() ); + + // Register the add bindings command vscode.commands.registerCommand( - "cloudflare-workers-bindings.addEntry", + "cloudflare-workers-bindings.addBinding", async () => { await multiStepInput(context); } From e9d1018587c83156742216d3bb3f5f8d7f8ecf28 Mon Sep 17 00:00:00 2001 From: emily-shen <69125074+emily-shen@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:08:32 +0000 Subject: [PATCH 3/5] changeset --- .changeset/slimy-dots-hope.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/slimy-dots-hope.md diff --git a/.changeset/slimy-dots-hope.md b/.changeset/slimy-dots-hope.md new file mode 100644 index 000000000000..f1a05aca9503 --- /dev/null +++ b/.changeset/slimy-dots-hope.md @@ -0,0 +1,5 @@ +--- +"cloudflare-workers-bindings-extension": minor +--- + +feat: add ui to add a binding via the extension From cc97bed3cb7af655d8f05c2e2441b60cda85c1c3 Mon Sep 17 00:00:00 2001 From: emily-shen <69125074+emily-shen@users.noreply.github.com> Date: Thu, 19 Dec 2024 13:19:57 +0000 Subject: [PATCH 4/5] pr feedback --- .../src/add-binding.ts | 31 +++++++++++-------- .../src/extension.ts | 15 ++++++--- .../src/{bindings.ts => show-bindings.ts} | 0 .../src/wrangler.ts | 1 - 4 files changed, 28 insertions(+), 19 deletions(-) rename packages/cloudflare-workers-bindings-extension/src/{bindings.ts => show-bindings.ts} (100%) diff --git a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts index 450ccdee31e9..861ee0c840fa 100644 --- a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts +++ b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts @@ -10,7 +10,7 @@ import { window, workspace, } from "vscode"; -import { getConfigUri } from "./bindings"; +import { getConfigUri } from "./show-bindings"; import { importWrangler } from "./wrangler"; class BindingType implements QuickPickItem { @@ -22,7 +22,7 @@ class BindingType implements QuickPickItem { ) {} } -export async function multiStepInput(context: ExtensionContext) { +export async function addBindingFlow(context: ExtensionContext) { const bindingTypes: BindingType[] = [ new BindingType( "KV", @@ -56,16 +56,13 @@ export async function multiStepInput(context: ExtensionContext) { async function collectInputs() { const state = {} as Partial; - await MultiStepInput.run((input) => pickResourceGroup(input, state)); + await MultiStepInput.run((input) => pickBindingType(input, state)); return state as State; } const title = "Add binding"; - async function pickResourceGroup( - input: MultiStepInput, - state: Partial - ) { + async function pickBindingType(input: MultiStepInput, state: Partial) { const pick = await input.showQuickPick({ title, step: 1, @@ -76,10 +73,13 @@ export async function multiStepInput(context: ExtensionContext) { typeof state.bindingType !== "string" ? state.bindingType : undefined, }); state.bindingType = pick as BindingType; - return (input: MultiStepInput) => inputName(input, state); + return (input: MultiStepInput) => inputBindingName(input, state); } - async function inputName(input: MultiStepInput, state: Partial) { + async function inputBindingName( + input: MultiStepInput, + state: Partial + ) { let name = await input.showInputBox({ title, step: 2, @@ -90,12 +90,17 @@ export async function multiStepInput(context: ExtensionContext) { placeholder: `e.g. MY_BINDING`, }); state.name = name; - return () => addToToml(state); + return () => addToConfig(state); } - async function addToToml(state: Partial) { + async function addToConfig(state: Partial) { const configUri = await getConfigUri(); if (!configUri) { + // for some reason, if we just throw an error it doesn't surface properly when triggered by the button in the welcome view + window.showErrorMessage( + "Unable to locate Wrangler configuration file — have you opened a project with a wrangler.json(c) or wrangler.toml file?", + {} + ); return null; } const workspaceFolder = workspace.getWorkspaceFolder(configUri); @@ -106,7 +111,7 @@ export async function multiStepInput(context: ExtensionContext) { const wrangler = importWrangler(workspaceFolder.uri.fsPath); - await workspace.openTextDocument(configUri).then((doc) => { + workspace.openTextDocument(configUri).then((doc) => { window.showTextDocument(doc); try { wrangler.experimental_patchConfig(configUri.path, { @@ -132,7 +137,7 @@ binding = "${state.name}" return name === "SOME_KV_BINDING" ? "Name not unique" : undefined; } - const state = await collectInputs(); + await collectInputs(); } // ------------------------------------------------------- diff --git a/packages/cloudflare-workers-bindings-extension/src/extension.ts b/packages/cloudflare-workers-bindings-extension/src/extension.ts index 3ce99f903cfb..d10f1dfc6742 100644 --- a/packages/cloudflare-workers-bindings-extension/src/extension.ts +++ b/packages/cloudflare-workers-bindings-extension/src/extension.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -import { multiStepInput } from "./add-binding"; -import { BindingsProvider } from "./bindings"; +import { addBindingFlow } from "./add-binding"; +import { BindingsProvider } from "./show-bindings"; export type Result = { bindingsProvider: BindingsProvider; @@ -34,14 +34,19 @@ export async function activate( ); // Register the add bindings command - vscode.commands.registerCommand( + const addBindingCommand = vscode.commands.registerCommand( "cloudflare-workers-bindings.addBinding", async () => { - await multiStepInput(context); + await addBindingFlow(context); } ); // Cleanup when the extension is deactivated - context.subscriptions.push(bindingsView, watcher, refreshCommand); + context.subscriptions.push( + bindingsView, + watcher, + refreshCommand, + addBindingCommand + ); return { bindingsProvider, diff --git a/packages/cloudflare-workers-bindings-extension/src/bindings.ts b/packages/cloudflare-workers-bindings-extension/src/show-bindings.ts similarity index 100% rename from packages/cloudflare-workers-bindings-extension/src/bindings.ts rename to packages/cloudflare-workers-bindings-extension/src/show-bindings.ts diff --git a/packages/cloudflare-workers-bindings-extension/src/wrangler.ts b/packages/cloudflare-workers-bindings-extension/src/wrangler.ts index 3f23a1f4e6a9..2e35d08288e2 100644 --- a/packages/cloudflare-workers-bindings-extension/src/wrangler.ts +++ b/packages/cloudflare-workers-bindings-extension/src/wrangler.ts @@ -1,5 +1,4 @@ import * as path from "path"; -import * as vscode from "vscode"; export function importWrangler( workspaceRoot: string From d587c3013c921c52c702c7a73cb7294bc24802a8 Mon Sep 17 00:00:00 2001 From: emily-shen <69125074+emily-shen@users.noreply.github.com> Date: Thu, 19 Dec 2024 13:21:05 +0000 Subject: [PATCH 5/5] fixup --- .../src/add-binding.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts index 861ee0c840fa..ec3e387c5561 100644 --- a/packages/cloudflare-workers-bindings-extension/src/add-binding.ts +++ b/packages/cloudflare-workers-bindings-extension/src/add-binding.ts @@ -16,7 +16,7 @@ import { importWrangler } from "./wrangler"; class BindingType implements QuickPickItem { constructor( public label: string, - public description?: string, + public configKey?: string, public detail?: string, public iconPath?: Uri ) {} @@ -115,7 +115,7 @@ export async function addBindingFlow(context: ExtensionContext) { window.showTextDocument(doc); try { wrangler.experimental_patchConfig(configUri.path, { - [state.bindingType?.description!]: [{ binding: state.name! }], + [state.bindingType?.configKey!]: [{ binding: state.name! }], }); window.showInformationMessage(`Created binding '${state.name}'`); } catch { @@ -123,7 +123,7 @@ export async function addBindingFlow(context: ExtensionContext) { `Unable to directly add binding to config file. A snippet has been copied to clipboard - please paste this into your config file.` ); - const patch = `[[${state.bindingType?.description!}]] + const patch = `[[${state.bindingType?.configKey!}]] binding = "${state.name}" `;