Skip to content

Commit cae6147

Browse files
amazonq: vscode walkthrough (aws#4739)
- Creates the Amazon Q walkthrough - GIFs still need to be created, we are waiting on those but we can merge for now - When the user logs in to Amazon Q the first time they will be shown the walkthrough page. It will never show again - We have telemetry for when the walkthrough is shown through our "first login" automation, and when certain events are triggered in the walkthrough such as opening the chat Signed-off-by: Nikolas Komonen <[email protected]>
1 parent 9b9bf61 commit cae6147

File tree

9 files changed

+146
-4
lines changed

9 files changed

+146
-4
lines changed

packages/amazonq/package.json

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,58 @@
798798
"fontCharacter": "\\f1c3"
799799
}
800800
}
801-
}
801+
},
802+
"walkthroughs": [
803+
{
804+
"id": "aws.amazonq.walkthrough",
805+
"title": "Meet Amazon Q",
806+
"description": "Your AI assistant",
807+
"steps": [
808+
{
809+
"id": "aws.amazonq.walkthrough.chat",
810+
"title": "Ask using chat",
811+
"description": "Amazon Q answers software development questions, writes code based on your current file, and cites sources.\n\nUse the right-click menu for quick commands.\n\n[Open Chat](command:_aws.amazonq.walkthrough.focusChat)",
812+
"media": {
813+
"image": "placeholder.jpg",
814+
"altText": "Gif of the right click context menu opening Amazon Q chat"
815+
},
816+
"completionEvents": [
817+
"onCommand:_aws.amazonq.walkthrough.focusChat"
818+
]
819+
},
820+
{
821+
"id": "aws.amazonq.walkthrough.inlineSuggestions",
822+
"title": "Get inline code suggestions",
823+
"description": "Amazon Q suggests code as you type based on your open files. Accepted suggestions from licensed code will go into the 'Code Reference Log'.",
824+
"media": {
825+
"image": "placeholder.jpg",
826+
"altText": "Gif of Amazon Q Inline Suggestions feature"
827+
}
828+
},
829+
{
830+
"id": "aws.amazonq.walkthrough.securityScan",
831+
"title": "Check for security vulnerabilities",
832+
"description": "Amazon Q scans your code to identify security vulnerabilities and suggests fixes.",
833+
"media": {
834+
"image": "placeholder.jpg",
835+
"altText": "Gif of a security scan"
836+
}
837+
},
838+
{
839+
"id": "aws.amazonq.walkthrough.settings",
840+
"title": "Access settings and options",
841+
"description": "Pause inline suggestions, open the Code Reference Log, access Settings, and more from the Amazon Q menu.\n\n[Open the status bar menu](command:_aws.amazonq.walkthrough.listCommands)",
842+
"media": {
843+
"image": "placeholder.jpg",
844+
"altText": "Gif of opening the Amazon Q status bar menu"
845+
},
846+
"completionEvents": [
847+
"onCommand:_aws.amazonq.walkthrough.listCommands"
848+
]
849+
}
850+
]
851+
}
852+
]
802853
},
803854
"engines": {
804855
"npm": "^10.1.0",

packages/amazonq/placeholder.jpg

2.35 KB
Loading

packages/core/src/amazonq/activation.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode'
77
import { ExtensionContext, window } from 'vscode'
8-
import { AmazonQChatViewProvider } from './webview/webView'
8+
import { AmazonQChatViewProvider, focusAmazonQChatWalkthrough } from './webview/webView'
99
import { init as cwChatAppInit } from '../codewhispererChat/app'
1010
import { init as featureDevChatAppInit } from '../amazonqFeatureDev/app'
1111
import { init as gumbyChatAppInit } from '../amazonqGumby/app'
@@ -17,6 +17,8 @@ import { activateBadge } from './util/viewBadgeHandler'
1717
import { telemetry } from '../shared/telemetry/telemetry'
1818
import { focusAmazonQPanel } from '../auth/ui/vue/show'
1919
import { amazonQHelpUrl } from '../shared/constants'
20+
import { openAmazonQWalkthrough } from './onboardingPage/walkthrough'
21+
import { listCodeWhispererCommandsWalkthrough } from '../codewhisperer/ui/statusBarMenu'
2022

2123
export async function activate(context: ExtensionContext) {
2224
const appInitContext = DefaultAmazonQAppInitContext.instance
@@ -37,7 +39,10 @@ export async function activate(context: ExtensionContext) {
3739
webviewOptions: {
3840
retainContextWhenHidden: true,
3941
},
40-
})
42+
}),
43+
focusAmazonQChatWalkthrough.register(),
44+
openAmazonQWalkthrough.register(),
45+
listCodeWhispererCommandsWalkthrough.register()
4146
)
4247

4348
amazonQWelcomeCommand.register(context, cwcWebViewToAppsPublisher)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import globals from '../../shared/extensionGlobals'
7+
import { VSCODE_EXTENSION_ID } from '../../shared/extensions'
8+
import { Commands } from '../../shared/vscode/commands2'
9+
import vscode from 'vscode'
10+
11+
/**
12+
* Show the Amazon Q walkthrough one time forever when the user adds an Amazon Q connection.
13+
* All subsequent calls to this do nothing.
14+
*/
15+
export async function showAmazonQWalkthroughOnce(
16+
state = globals.context.globalState,
17+
showWalkthrough = () => openAmazonQWalkthrough.execute()
18+
) {
19+
const hasShownWalkthroughId = 'aws.amazonq.hasShownWalkthrough'
20+
const hasShownWalkthrough = state.get(hasShownWalkthroughId, false)
21+
if (hasShownWalkthrough) {
22+
return
23+
}
24+
await state.update(hasShownWalkthroughId, true)
25+
await showWalkthrough()
26+
}
27+
28+
/**
29+
* Opens the Amazon Q Walkthrough.
30+
* We wrap the actual command so that we can get telemetry from it.
31+
*/
32+
export const openAmazonQWalkthrough = Commands.declare(`_aws.amazonq.walkthrough.show`, () => async () => {
33+
await vscode.commands.executeCommand(
34+
'workbench.action.openWalkthrough',
35+
`${VSCODE_EXTENSION_ID.amazonq}#aws.amazonq.walkthrough`
36+
)
37+
})

packages/core/src/amazonq/webview/webView.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import { MessagePublisher } from '../messages/messagePublisher'
2121
import { TabType } from './ui/storages/tabsStorage'
2222
import { deactivateInitialViewBadge, shouldShowBadge } from '../util/viewBadgeHandler'
2323
import { telemetry } from '../../shared/telemetry/telemetry'
24+
import { Commands } from '../../shared/vscode/commands2'
25+
import vscode from 'vscode'
2426

2527
export class AmazonQChatViewProvider implements WebviewViewProvider {
2628
public static readonly viewType = 'aws.AmazonQChatView'
@@ -79,3 +81,8 @@ export class AmazonQChatViewProvider implements WebviewViewProvider {
7981
deactivateInitialViewBadge()
8082
}
8183
}
84+
85+
/** For use by the walkthrough page only. We need this for telemetry. */
86+
export const focusAmazonQChatWalkthrough = Commands.declare('_aws.amazonq.walkthrough.focusChat', () => async () => {
87+
await vscode.commands.executeCommand('aws.AmazonQChatView.focus')
88+
})

packages/core/src/codewhisperer/ui/statusBarMenu.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,14 @@ export const listCodeWhispererCommands = Commands.declare({ id: listCodeWhispere
109109
ignoreFocusOut: false,
110110
}).prompt()
111111
})
112+
113+
/**
114+
* Does what {@link listCodeWhispererCommands} does, must only be used by the walkthrough for telemetry
115+
* purposes.
116+
*/
117+
export const listCodeWhispererCommandsWalkthrough = Commands.declare(
118+
`_aws.amazonq.walkthrough.listCommands`,
119+
() => async () => {
120+
await listCodeWhispererCommands.execute()
121+
}
122+
)

packages/core/src/codewhisperer/util/authUtil.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { indent } from '../../shared/utilities/textUtilities'
3737
import { VSCODE_EXTENSION_ID } from '../../shared/extensions'
3838
import { isExtensionActive } from '../../shared/utilities'
3939
import { showReauthenticateMessage } from '../../shared/utilities/messages'
40+
import { showAmazonQWalkthroughOnce } from '../../amazonq/onboardingPage/walkthrough'
4041

4142
/** Backwards compatibility for connections w pre-chat scopes */
4243
export const codeWhispererCoreScopes = [...scopesSsoAccountAccess, ...scopesCodeWhispererCore]
@@ -251,6 +252,8 @@ export class AuthUtil {
251252
conn = await this.auth.reauthenticate(conn)
252253
}
253254

255+
await showAmazonQWalkthroughOnce()
256+
254257
return this.secondaryAuth.useNewConnection(conn)
255258
}
256259

@@ -270,6 +273,8 @@ export class AuthUtil {
270273
conn = await this.auth.reauthenticate(conn)
271274
}
272275

276+
await showAmazonQWalkthroughOnce()
277+
273278
return this.secondaryAuth.useNewConnection(conn)
274279
}
275280

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import assert from 'assert'
7+
import { showAmazonQWalkthroughOnce } from '../../../amazonq/onboardingPage/walkthrough'
8+
import { FakeMemento } from '../../fakeExtensionContext'
9+
import sinon from 'sinon'
10+
11+
describe('showAmazonQWalkthroughOnce', function () {
12+
it('only shows once', async function () {
13+
const state = new FakeMemento()
14+
const showWalkthroughStub = sinon.stub()
15+
assert.deepStrictEqual(showWalkthroughStub.callCount, 0)
16+
await showAmazonQWalkthroughOnce(state, showWalkthroughStub)
17+
// Show walkthrough since our state indicates we haven't shown before
18+
assert.deepStrictEqual(showWalkthroughStub.callCount, 1)
19+
20+
await showAmazonQWalkthroughOnce(state, showWalkthroughStub)
21+
// On the second call we do not show again since we've shown before.
22+
assert.deepStrictEqual(showWalkthroughStub.callCount, 1)
23+
})
24+
})

packages/core/src/test/codewhisperer/util/authUtil.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ import {
1414
import { getTestWindow } from '../../shared/vscode/window'
1515
import { SeverityLevel } from '../../shared/vscode/message'
1616
import { createBuilderIdProfile, createSsoProfile, createTestAuth } from '../../credentials/testUtil'
17-
import { captureEventOnce } from '../../testUtil'
17+
import { captureEventOnce, tryRegister } from '../../testUtil'
1818
import { Connection, isAnySsoConnection, isBuilderIdConnection } from '../../../auth/connection'
1919
import { Auth } from '../../../auth/auth'
20+
import { openAmazonQWalkthrough } from '../../../amazonq/onboardingPage/walkthrough'
2021

2122
const enterpriseSsoStartUrl = 'https://enterprise.awsapps.com/start'
2223

@@ -27,6 +28,7 @@ describe('AuthUtil', async function () {
2728
beforeEach(async function () {
2829
auth = createTestAuth()
2930
authUtil = new AuthUtil(auth)
31+
tryRegister(openAmazonQWalkthrough)
3032
})
3133

3234
afterEach(async function () {

0 commit comments

Comments
 (0)