diff --git a/packages/core/package.nls.json b/packages/core/package.nls.json index 99461cd1069..92b7600fa50 100644 --- a/packages/core/package.nls.json +++ b/packages/core/package.nls.json @@ -437,5 +437,5 @@ "AWS.toolkit.lambda.walkthrough.step1.description": "Locally test and debug your code.", "AWS.toolkit.lambda.walkthrough.step2.title": "Deploy to the cloud", "AWS.toolkit.lambda.walkthrough.step2.description": "Test your application in the cloud from within VS Code. \n\nNote: The AWS CLI and the SAM CLI require AWS Credentials to interact with the cloud. For information on setting up your credentials, see [Authentication and access credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html). \n\n[Configure credentials](command:aws.toolkit.lambda.walkthrough.credential)", - "AWS.toolkit.lambda.serverlessLand.quickpickTitle": "Create Lambda Application from template" + "AWS.toolkit.lambda.serverlessLand.quickpickTitle": "Create application with Serverless template" } diff --git a/packages/core/src/awsService/appBuilder/serverlessLand/main.ts b/packages/core/src/awsService/appBuilder/serverlessLand/main.ts index 3b4efbacf04..4b76901cf4e 100644 --- a/packages/core/src/awsService/appBuilder/serverlessLand/main.ts +++ b/packages/core/src/awsService/appBuilder/serverlessLand/main.ts @@ -115,9 +115,8 @@ async function openReadmeFile(config: CreateServerlessLandWizardForm): Promise { + const metadataPath = instance.getMetadataPath() + instance.loadMetadata(metadataPath).catch((err) => { throw new ToolkitError(`Failed to load metadata: ${err}`) }) return instance } + public getMetadataPath(): string { + return globals.context.asAbsolutePath('dist/src/serverlessLand/metadata.json') + } + /** * Loads metadata from a JSON file * @param metadataPath Path to the metadata JSON file @@ -117,6 +114,16 @@ export class MetadataManager { })) } + public getUrl(pattern: string): string { + const patternData = this.metadata?.patterns?.[pattern] + if (!patternData || !patternData.implementation) { + return '' + } + const asset = patternData.implementation[0].assetName + + return `https://serverlessland.com/patterns/${asset}` + } + /** * Gets available Infrastructure as Code options for a specific pattern * @param pattern The pattern name to get IaC options for diff --git a/packages/core/src/awsService/appBuilder/serverlessLand/wizard.ts b/packages/core/src/awsService/appBuilder/serverlessLand/wizard.ts index 7bcc17b780c..29a7efa3637 100644 --- a/packages/core/src/awsService/appBuilder/serverlessLand/wizard.ts +++ b/packages/core/src/awsService/appBuilder/serverlessLand/wizard.ts @@ -22,6 +22,7 @@ export interface CreateServerlessLandWizardForm { pattern: string runtime: string iac: string + assetName: string } function promptPattern(metadataManager: MetadataManager) { @@ -37,11 +38,7 @@ function promptPattern(metadataManager: MetadataManager) { data: p.label, buttons: [ { - iconPath: new vscode.ThemeIcon('github'), - tooltip: 'Open in GitHub', - }, - { - iconPath: new vscode.ThemeIcon('open-preview'), + iconPath: new vscode.ThemeIcon('link-external'), tooltip: 'Open in Serverless Land', }, ], @@ -74,7 +71,7 @@ function promptRuntime(metadataManager: MetadataManager, pattern: string | undef { title: localize('AWS.serverlessLand.initWizard.runtime.prompt', 'Select Runtime'), placeholder: 'Choose a runtime for your project', - buttons: [vscode.QuickInputButtons.Back], + buttons: createCommonButtons(), } ) } @@ -97,7 +94,7 @@ function promptIac(metadataManager: MetadataManager, pattern: string | undefined { title: localize('AWS.serverlessLand.initWizard.iac.prompt', 'Select IaC'), placeholder: 'Choose an IaC option for your project', - buttons: [vscode.QuickInputButtons.Back], + buttons: createCommonButtons(), } ) } @@ -105,16 +102,17 @@ function promptIac(metadataManager: MetadataManager, pattern: string | undefined function promptLocation() { return createFolderPrompt(vscode.workspace.workspaceFolders ?? [], { title: localize('AWS.serverlessLand.initWizard.location.prompt', 'Select Project Location'), - buttons: [vscode.QuickInputButtons.Back], - browseFolderDetail: 'Select a folder for your project', + buttons: createCommonButtons(), + browseFolderDetail: 'Select a parent folder for your project', }) } -function promptName() { +function promptName(location: vscode.Uri | undefined) { + const folderName = location ? path.basename(location.fsPath) : '' return createInputBox({ title: localize('AWS.serverlessLand.initWizard.name.prompt', 'Enter Project Name'), - placeholder: 'Enter a name for your new application', - buttons: [vscode.QuickInputButtons.Back], + placeholder: ` ${folderName}/: Enter a name for your new application`, + buttons: createCommonButtons(), validateInput: (value: string): string | undefined => { if (!value) { return 'Application name cannot be empty' @@ -143,6 +141,6 @@ export class CreateServerlessLandWizard extends Wizard promptRuntime(this.metadataManager, state.pattern)) this.form.iac.bindPrompter((state) => promptIac(this.metadataManager, state.pattern)) this.form.location.bindPrompter(() => promptLocation()) - this.form.name.bindPrompter(() => promptName()) + this.form.name.bindPrompter((state) => promptName(state.location)) } } diff --git a/packages/core/src/shared/ui/pickerPrompter.ts b/packages/core/src/shared/ui/pickerPrompter.ts index daa65246fed..eaf4a4e6b4c 100644 --- a/packages/core/src/shared/ui/pickerPrompter.ts +++ b/packages/core/src/shared/ui/pickerPrompter.ts @@ -12,6 +12,8 @@ import { Prompter, PromptResult, Transform } from './prompter' import { assign, isAsyncIterable } from '../utilities/collectionUtils' import { recentlyUsed } from '../localizedText' import { getLogger } from '../logger/logger' +import { openUrl } from '../utilities/vsCodeUtils' +import { MetadataManager } from '../../awsService/appBuilder/serverlessLand/metadataManager' const localize = nls.loadMessageBundle() @@ -143,6 +145,22 @@ export function createQuickPick( assign(mergedOptions, picker) picker.buttons = mergedOptions.buttons ?? [] + picker.onDidTriggerItemButton(async (event) => { + const metadataManager = MetadataManager.getInstance() + if (event.button.tooltip !== 'Open in Serverless Land') { + return + } + const selectedPattern = event.item + if (!selectedPattern) { + return + } + const patternUrl = metadataManager.getUrl(selectedPattern.label) + if (!patternUrl) { + return + } + await openUrl(vscode.Uri.parse(patternUrl)) + }) + const prompter = mergedOptions.filterBoxInputSettings !== undefined ? new FilterBoxQuickPickPrompter(picker, mergedOptions) diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index c662436830d..749b05f16ec 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -1327,24 +1327,29 @@ "group": "1_account@3" }, { - "command": "aws.lambda.createNewSamApp", + "command": "aws.toolkit.lambda.createServerlessLandProject", "when": "view == aws.explorer", "group": "3_lambda@1" }, { - "command": "aws.launchConfigForm", + "command": "aws.lambda.createNewSamApp", "when": "view == aws.explorer", "group": "3_lambda@2" }, + { + "command": "aws.launchConfigForm", + "when": "view == aws.explorer", + "group": "3_lambda@3" + }, { "command": "aws.deploySamApplication", "when": "config.aws.samcli.legacyDeploy && view == aws.explorer", - "group": "3_lambda@3" + "group": "3_lambda@4" }, { "command": "aws.samcli.sync", "when": "!config.aws.samcli.legacyDeploy && view == aws.explorer", - "group": "3_lambda@3" + "group": "3_lambda@4" }, { "submenu": "aws.toolkit.submenu.feedback", diff --git a/packages/toolkit/scripts/build/copyFiles.ts b/packages/toolkit/scripts/build/copyFiles.ts index 6cea899b4ca..7d065040416 100644 --- a/packages/toolkit/scripts/build/copyFiles.ts +++ b/packages/toolkit/scripts/build/copyFiles.ts @@ -69,6 +69,19 @@ const tasks: CopyTask[] = [ destination: path.join('src', 'stepFunctions', 'asl', 'aslServer.js'), }, + // Serverless Land + { + target: path.join( + '../../node_modules/aws-core-vscode', + 'src', + 'awsService', + 'appBuilder', + 'serverlessLand', + 'metadata.json' + ), + destination: path.join('src', 'serverlessLand', 'metadata.json'), + }, + // Vue { target: path.join('../core', 'resources', 'js', 'vscode.js'),