Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

samInitWizard back buttons + other housekeeping #364

Merged
merged 8 commits into from
Mar 14, 2019
4 changes: 2 additions & 2 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@
"AWS.samcli.detect.settings.updated": "Settings updated.",
"AWS.samcli.detect.settings.not.updated": "No settings changes necessary.",
"AWS.samcli.deploy.region.prompt": "Which AWS Region would you like to deploy to?",
"AWS.samcli.deploy.region.previousRegion": "Selected Previously",
"AWS.samcli.deploy.s3Bucket.region": "S3 bucket must be in selected region: {0}",
"AWS.samcli.deploy.s3Bucket.prompt": "Enter the AWS S3 bucket to which your code should be deployed",
"AWS.samcli.deploy.s3Bucket.error": "S3 bucket cannot be empty",
Expand Down Expand Up @@ -135,7 +134,7 @@
"AWS.samcli.userChoice.browse": "Locate SAM CLI...",
"AWS.samcli.userChoice.visit.install.url": "Get SAM CLI",
"AWS.samcli.userChoice.update.awstoolkit.url": "Update AWS Toolkit",
"AWS.samcli.initWizard.location.prompt": "Select a location for your new project",
"AWS.samcli.initWizard.location.prompt": "Select a workspace folder for your new project",
bryceitoc9 marked this conversation as resolved.
Show resolved Hide resolved
"AWS.samcli.initWizard.name.prompt": "Choose a name for your new application",
"AWS.samcli.initWizard.name.placeholder": "application name",
"AWS.samcli.initWizard.name.browse.label": "Browse...",
Expand All @@ -145,6 +144,7 @@
"AWS.samcli.initWizard.runtime.prompt": "Select a SAM Application Runtime",
"AWS.samcli.initWizard.source.error.notFound": "Project created successfully, but main source code file not found: {0}",
"AWS.samcli.initWizard.source.error.notInWorkspace": "Could not open file '{0}'. If this file exists on disk, try adding it to your workspace.",
"AWS.samcli.wizard.selectedPreviously": "Selected Previously",
"AWS.generic.response.no": "No",
"AWS.generic.response.yes": "Yes",
"AWS.template.error.showErrorDetails.title": "Error details for",
Expand Down
39 changes: 7 additions & 32 deletions src/lambda/wizards/samDeployWizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ class DefaultSamDeployWizardContext implements SamDeployWizardContext {
* @returns vscode.Uri of a Sam Template. undefined represents cancel.
*/
public async promptUserForSamTemplate(initialValue?: vscode.Uri): Promise<vscode.Uri | undefined> {
const logger = getLogger()
const workspaceFolders = this.workspaceFolders || []

const quickPick = picker.createQuickPick<SamTemplateQuickPickItem>({
Expand All @@ -96,28 +95,15 @@ class DefaultSamDeployWizardContext implements SamDeployWizardContext {
const choices = await picker.promptUser<SamTemplateQuickPickItem>({
picker: quickPick,
})
const val = picker.verifySinglePickerOutput<SamTemplateQuickPickItem>(choices)

if (!choices || choices.length === 0) {
return undefined
}

if (choices.length > 1) {
logger.warn(
`Received ${choices.length} responses from user, expected 1.` +
' Cancelling to prevent deployment of unexpected template.'
)

return undefined
}

return choices[0].uri
return val ? val.uri : undefined
}

public async promptUserForRegion(
regionProvider: RegionProvider,
initialRegionCode: string
): Promise<string | undefined> {
const logger = getLogger()
const regionData = await regionProvider.getRegionData()

const quickPick = picker.createQuickPick<vscode.QuickPickItem>({
Expand All @@ -138,7 +124,7 @@ class DefaultSamDeployWizardContext implements SamDeployWizardContext {
// this will make it so it always shows even when searching for something else
alwaysShow: r.regionCode === initialRegionCode,
description: r.regionCode === initialRegionCode ?
localize('AWS.samcli.deploy.region.previousRegion', 'Selected Previously') : ''
localize('AWS.samcli.wizard.selectedPreviously', 'Selected Previously') : ''
}
)),
buttons: [
Expand All @@ -154,21 +140,9 @@ class DefaultSamDeployWizardContext implements SamDeployWizardContext {
}
}
})
const val = picker.verifySinglePickerOutput(choices)

if (!choices || choices.length === 0) {
return undefined
}

if (choices.length > 1) {
logger.warn(
`Received ${choices.length} responses from user, expected 1.` +
' Cancelling to prevent deployment of unexpected template.'
)

return undefined
}

return choices[0].detail
return val ? val.detail : undefined
}

/**
Expand Down Expand Up @@ -351,6 +325,7 @@ class SamTemplateQuickPickItem implements vscode.QuickPickItem {
}

public static getLabel(uri: vscode.Uri): string {
const logger = getLogger()
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri)

if (workspaceFolder) {
Expand All @@ -360,7 +335,7 @@ class SamTemplateQuickPickItem implements vscode.QuickPickItem {
}

// We shouldn't find sam templates outside of a workspace folder. If we do, show the full path.
console.warn(
logger.warn(
`Unexpected situation: detected SAM Template ${uri.fsPath} not found within a workspace folder.`
)

Expand Down
215 changes: 122 additions & 93 deletions src/lambda/wizards/samInitWizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,53 +13,143 @@ import * as os from 'os'
import * as path from 'path'
import * as vscode from 'vscode'
import { SamCliInitArgs } from '../../shared/sam/cli/samCliInit'
import * as input from '../../shared/ui/input'
import * as picker from '../../shared/ui/picker'
import * as lambdaRuntime from '../models/samLambdaRuntime'
import { MultiStepWizard, WizardStep } from '../wizards/multiStepWizard'

export interface CreateNewSamAppWizardContext {
readonly lambdaRuntimes: immutable.Set<lambdaRuntime.SamLambdaRuntime>
readonly workspaceFolders: vscode.WorkspaceFolder[] | undefined

showInputBox(
options?: vscode.InputBoxOptions,
token?: vscode.CancellationToken
): Thenable<string | undefined>
promptUserForRuntime(
currRuntime?: lambdaRuntime.SamLambdaRuntime
): Promise<lambdaRuntime.SamLambdaRuntime | undefined>

promptUserForLocation(): Promise<vscode.Uri | undefined>

promptUserForName(): Promise<string | undefined>

showOpenDialog(
options: vscode.OpenDialogOptions
): Thenable<vscode.Uri[] | undefined>

showQuickPick(
items: string[] | Thenable<string[]>,
options: vscode.QuickPickOptions & { canPickMany: true },
token?: vscode.CancellationToken
): Thenable<string[] | undefined>
showQuickPick(
items: string[] | Thenable<string[]>,
options?: vscode.QuickPickOptions,
token?: vscode.CancellationToken
): Thenable<string | undefined>
showQuickPick<T extends vscode.QuickPickItem>(
items: T[] | Thenable<T[]>,
options: vscode.QuickPickOptions & { canPickMany: true },
token?: vscode.CancellationToken
): Thenable<T[] | undefined>
showQuickPick<T extends vscode.QuickPickItem>(
items: T[] | Thenable<T[]>,
options?: vscode.QuickPickOptions,
token?: vscode.CancellationToken
): Thenable<T | undefined>
}

class DefaultCreateNewSamAppWizardContext implements CreateNewSamAppWizardContext {
public readonly lambdaRuntimes = lambdaRuntime.samLambdaRuntimes
public readonly showInputBox = vscode.window.showInputBox
public readonly showOpenDialog = vscode.window.showOpenDialog
public readonly showQuickPick = vscode.window.showQuickPick

public get workspaceFolders(): vscode.WorkspaceFolder[] | undefined {
return vscode.workspace.workspaceFolders
}

public async promptUserForRuntime(
currRuntime?: lambdaRuntime.SamLambdaRuntime
): Promise<lambdaRuntime.SamLambdaRuntime | undefined> {
const quickPick = picker.createQuickPick<vscode.QuickPickItem>({
options: {
ignoreFocusOut: true,
title: localize(
'AWS.samcli.initWizard.runtime.prompt',
'Select a SAM Application Runtime'
),
value: currRuntime ? currRuntime : ''
},
items: this.lambdaRuntimes
.toArray()
.sort()
.map(runtime => ({
label: runtime,
alwaysShow: runtime === currRuntime,
description: runtime === currRuntime ?
localize('AWS.samcli.wizard.selectedPreviously', 'Selected Previously') : ''
}))
})

const choices = await picker.promptUser({
picker: quickPick
})
const val = picker.verifySinglePickerOutput(choices)

return val ? val.label as lambdaRuntime.SamLambdaRuntime : undefined
}

public async promptUserForLocation(): Promise<vscode.Uri | undefined> {
const items: FolderQuickPickItem[] = (this.workspaceFolders || [])
.map<FolderQuickPickItem>(f => new WorkspaceFolderQuickPickItem(f))
.concat([new BrowseFolderQuickPickItem(this)])

const quickPick = picker.createQuickPick({
options: {
ignoreFocusOut: true,
title: localize(
'AWS.samcli.initWizard.location.prompt',
'Select a workspace folder for your new project'
)
},
items: items,
buttons: [
vscode.QuickInputButtons.Back
]
})

const choices = await picker.promptUser({
picker: quickPick,
onDidTriggerButton: (button, resolve, reject) => {
if (button === vscode.QuickInputButtons.Back) {
resolve(undefined)
}
}
})
const val = picker.verifySinglePickerOutput<FolderQuickPickItem>(choices)

return val ? val.getUri() : undefined
}

public async promptUserForName(): Promise<string | undefined> {
const inputBox = input.createInputBox({
options: {
title: localize(
'AWS.samcli.initWizard.name.prompt',
'Choose a name for your new application'
),
placeHolder: localize(
'AWS.samcli.initWizard.name.placeholder',
'application name'
),
ignoreFocusOut: true,
},
buttons: [
vscode.QuickInputButtons.Back
]
})

return await input.promptUser({
inputBox: inputBox,
onValidateInput: (value: string) => {
if (!value) {
return localize(
'AWS.samcli.initWizard.name.error.empty',
'Application name cannot be empty'
)
}

if (value.includes(path.sep)) {
return localize(
'AWS.samcli.initWizard.name.error.pathSep',
'The path separator ({0}) is not allowed in application names',
path.sep
)
}

return undefined
},
onDidTriggerButton: (button, resolve, reject) => {
if (button === vscode.QuickInputButtons.Back) {
resolve(undefined)
}
}
})
}
}

export class CreateNewSamAppWizard extends MultiStepWizard<SamCliInitArgs> {
Expand Down Expand Up @@ -90,80 +180,19 @@ export class CreateNewSamAppWizard extends MultiStepWizard<SamCliInitArgs> {
}

private readonly RUNTIME: WizardStep = async () => {
const runtimeItems = this.context.lambdaRuntimes
.toArray()
.sort()
.map(runtime => ({ label: runtime }))

const result = await this.context.showQuickPick<vscode.QuickPickItem>(runtimeItems, {
ignoreFocusOut: true,
placeHolder: localize(
'AWS.samcli.initWizard.runtime.prompt',
'Select a SAM Application Runtime'
)
})

if (!result) {
return undefined
}

this.runtime = result.label as lambdaRuntime.SamLambdaRuntime
this.runtime = await this.context.promptUserForRuntime(this.runtime)

return this.LOCATION
return this.runtime ? this.LOCATION : undefined
}

private readonly LOCATION: WizardStep = async () => {
const choices: FolderQuickPickItem[] = (this.context.workspaceFolders || [])
.map<FolderQuickPickItem>(f => new WorkspaceFolderQuickPickItem(f))
.concat([new BrowseFolderQuickPickItem(this.context)])

const selection = await this.context.showQuickPick(choices, {
ignoreFocusOut: true,
placeHolder: localize(
'AWS.samcli.initWizard.location.prompt',
'Select a location for your new project'
)
})
if (!selection) {
return this.RUNTIME
}
this.location = await selection.getUri()
this.location = await this.context.promptUserForLocation()

return this.location ? this.NAME : this.RUNTIME
}

private readonly NAME: WizardStep = async () => {
this.name = await this.context.showInputBox({
value: 'my-sam-app',
prompt: localize(
'AWS.samcli.initWizard.name.prompt',
'Choose a name for your new application'
),
placeHolder: localize(
'AWS.samcli.initWizard.name.placeholder',
'application name'
),
ignoreFocusOut: true,

validateInput(value: string): string | undefined | null | Thenable<string | undefined | null> {
if (!value) {
return localize(
'AWS.samcli.initWizard.name.error.empty',
'Application name cannot be empty'
)
}

if (value.includes(path.sep)) {
return localize(
'AWS.samcli.initWizard.name.error.pathSep',
'The path separator ({0}) is not allowed in application names',
path.sep
)
}

return undefined
}
})
this.name = await this.context.promptUserForName()

return this.name ? undefined : this.LOCATION
}
Expand Down
Loading