Skip to content

Commit 68f5a44

Browse files
authWebview: UI buttons open auth webview (#3539)
* refactor: make AuthCommandDeclarations singleton This makes this class a singleton and updates existing use cases Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: Developer Tools 'Start' button opens webview When the 'Start' node for CC or CW is selected this will now have the webview open instead of the builder id setup prompts - still need to setup the start button to cause webview to open on specific service item - Also added a fallback when not in dev mode to use the old add connection functionality. Signed-off-by: Nikolas Komonen <[email protected]> * uiOpenView: 'Start' from developer tools opens with service already selected When the user clicks the 'Start' button the auth webview page will be openend with the specific service already selected. Eg: Clicking 'Start' in CodeCatalyst opens up the webview directly to CodeCatalyst Signed-off-by: Nikolas Komonen <[email protected]> * explorer: vscode command to show 'developer tools' root node - Creates vscode commands that can eventually be executed and will show the root node (cc, cw, ..) in the developer tools tree view Signed-off-by: Nikolas Komonen <[email protected]> * button in form to open node After the user has signed in with BuilderID to CC or CW, we will now show a button which can be clicked and will open the appropriate node in the 'Developer Tools' view. Signed-off-by: Nikolas Komonen <[email protected]> * fix: circular dependency Problem: The getStartedCommand is now used in multiple places outside of the explorer. This was causing a circular dependency. Solution: Move the getStartedCommand to the utils module Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: Resource Explorer credentials form button Adds a button once the resource explorer credentials are authenticated to open the Resource Explorer view Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: Identity Center form button opens node Now once CW is signed in with Identity Center we will show a button that expands the CW node in the Developer Tools menu Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: 'Add New Connection' quick pick opens webview In the connection selection quick pick the last option is 'Add New Connection' that previously led in to another vscode wizard. Now this instead opens the Add Connection webview. Signed-off-by: Nikolas Komonen <[email protected]> * codewhisperer: Update tests to point to new sso signup command Problem: Before the new auth webview, CW used a quickpick wizard for users to setup their required auth (sso, builderid). They used a specific command and ensured they used it in their unit tests. But now with the auth webview changes we will not be redirecting them to the quickpick wizard anymore. Instead, we will redirect users to the webview. This uses a different command name. Solution: Update the unit tests to point to the new vscode command name that will be used. Additionally, since the whole auth webview feature is not ready we fallback to the old functionality if the user is not in dev mode (an aws extension setting). Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: change auth id to lowercase Changes the IDs of service to lowercase and in some cases certain names should be one word (CC and CW). Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: lowercase + single service id converts the service id values to lower case and makes some as single words Signed-off-by: Nikolas Komonen <[email protected]> * uiOpensView: aws.auth.showConnectionsPage > aws.auth.manageConnections Signed-off-by: Nikolas Komonen <[email protected]> --------- Signed-off-by: Nikolas Komonen <[email protected]>
1 parent eefc1cc commit 68f5a44

26 files changed

+386
-122
lines changed

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,7 @@
11081108
"when": "false"
11091109
},
11101110
{
1111-
"command": "aws.auth.showConnectionsPage",
1111+
"command": "aws.auth.manageConnections",
11121112
"when": "aws.isDevMode"
11131113
},
11141114
{
@@ -1872,7 +1872,7 @@
18721872
],
18731873
"aws.auth": [
18741874
{
1875-
"command": "aws.auth.addConnection",
1875+
"command": "aws.auth.manageConnections",
18761876
"group": "0@1"
18771877
},
18781878
{
@@ -2020,10 +2020,9 @@
20202020
"category": "%AWS.title%"
20212021
},
20222022
{
2023-
"command": "aws.auth.showConnectionsPage",
2023+
"command": "aws.auth.manageConnections",
20242024
"title": "%AWS.command.auth.showConnectionsPage%",
2025-
"category": "%AWS.title%",
2026-
"enablement": "aws.isDevMode"
2025+
"category": "%AWS.title%"
20272026
},
20282027
{
20292028
"command": "aws.auth.switchConnections",

package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"AWS.command.apig.invokeRemoteRestApi": "Invoke on AWS",
7777
"AWS.command.apig.invokeRemoteRestApi.cn": "Invoke on Amazon",
7878
"AWS.command.auth.addConnection": "Add New Connection",
79-
"AWS.command.auth.showConnectionsPage": "Show Auth Connections Page",
79+
"AWS.command.auth.showConnectionsPage": "Add New Connection",
8080
"AWS.command.auth.switchConnections": "Switch Connections",
8181
"AWS.command.auth.signout": "Sign out",
8282
"AWS.command.github": "View Source on GitHub",

src/auth/activation.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ export async function initialize(
2626
})
2727

2828
// TODO: To enable this in prod we need to remove the 'when' clause
29-
// for: '"command": "aws.auth.showConnectionsPage"' in package.json
29+
// for: '"command": "aws.auth.manageConnections"' in package.json
3030
registerCommandsWithVSCode(
3131
extensionContext,
32-
new AuthCommandDeclarations(),
32+
AuthCommandDeclarations.instance,
3333
new AuthCommandBackend(extensionContext)
3434
)
3535
}

src/auth/commands.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,40 @@
55
import * as vscode from 'vscode'
66
import { CommandDeclarations, Commands } from '../shared/vscode/commands2'
77
import { showAuthWebview } from './ui/vue/show'
8+
import { ServiceItemId, isServiceItemId } from './ui/vue/types'
9+
import { showConnectionsPageCommand } from './utils'
810

911
/**
1012
* The methods with backend logic for the Auth commands.
1113
*/
1214
export class AuthCommandBackend {
1315
constructor(private readonly extContext: vscode.ExtensionContext) {}
1416

15-
public async showConnectionsPage() {
16-
await showAuthWebview(this.extContext)
17+
public showConnectionsPage(serviceToShow?: ServiceItemId) {
18+
// Edge case where called by vscode UI and non ServiceItemId object
19+
// is passed in.
20+
if (!isServiceItemId(serviceToShow)) {
21+
serviceToShow = undefined
22+
}
23+
return showAuthWebview(this.extContext, serviceToShow)
1724
}
1825
}
1926

2027
/**
2128
* Declared commands related to Authentication in the toolkit.
2229
*/
2330
export class AuthCommandDeclarations implements CommandDeclarations<AuthCommandBackend> {
31+
static #instance: AuthCommandDeclarations
32+
33+
static get instance(): AuthCommandDeclarations {
34+
return (this.#instance ??= new AuthCommandDeclarations())
35+
}
36+
37+
private constructor() {}
38+
2439
public readonly declared = {
2540
showConnectionsPage: Commands.from(AuthCommandBackend).declareShowConnectionsPage({
26-
id: 'aws.auth.showConnectionsPage',
41+
id: showConnectionsPageCommand,
2742
}),
2843
} as const
2944
}

src/auth/ui/vue/authForms/manageBuilderId.vue

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
<div class="form-section">
2929
<div v-on:click="signout()" style="cursor: pointer; color: #75beff">Sign out</div>
3030
</div>
31+
32+
<div class="form-section">
33+
<button v-on:click="showNodeInView()">Open {{ name }} in Toolkit</button>
34+
</div>
3135
</div>
3236
</div>
3337
</div>
@@ -62,6 +66,7 @@ export default defineComponent({
6266
isConnected: false,
6367
builderIdCode: '',
6468
canShowAll: false,
69+
name: this.state.name,
6570
}
6671
},
6772
async created() {
@@ -84,6 +89,9 @@ export default defineComponent({
8489
8590
this.update()
8691
},
92+
showNodeInView() {
93+
this.state.showNodeInView()
94+
},
8795
},
8896
})
8997
@@ -93,9 +101,11 @@ export default defineComponent({
93101
abstract class BaseBuilderIdState implements AuthStatus {
94102
protected _stage: BuilderIdStage = 'START'
95103
104+
abstract get name(): string
96105
abstract get id(): AuthFormId
97106
protected abstract _startBuilderIdSetup(): Promise<void>
98107
abstract isAuthConnected(): Promise<boolean>
108+
abstract showNodeInView(): Promise<void>
99109
100110
async startBuilderIdSetup(): Promise<void> {
101111
this._stage = 'WAITING_ON_USER'
@@ -114,8 +124,12 @@ abstract class BaseBuilderIdState implements AuthStatus {
114124
}
115125
116126
export class CodeWhispererBuilderIdState extends BaseBuilderIdState {
127+
override get name(): string {
128+
return 'CodeWhisperer'
129+
}
130+
117131
override get id(): AuthFormId {
118-
return 'BUILDER_ID_CODE_WHISPERER'
132+
return 'builderIdCodeWhisperer'
119133
}
120134
121135
override isAuthConnected(): Promise<boolean> {
@@ -125,11 +139,19 @@ export class CodeWhispererBuilderIdState extends BaseBuilderIdState {
125139
protected override _startBuilderIdSetup(): Promise<void> {
126140
return client.startCodeWhispererBuilderIdSetup()
127141
}
142+
143+
override showNodeInView(): Promise<void> {
144+
return client.showCodeWhispererNode()
145+
}
128146
}
129147
130148
export class CodeCatalystBuilderIdState extends BaseBuilderIdState {
149+
override get name(): string {
150+
return 'CodeCatalyst'
151+
}
152+
131153
override get id(): AuthFormId {
132-
return 'BUILDER_ID_CODE_CATALYST'
154+
return 'builderIdCodeCatalyst'
133155
}
134156
135157
override isAuthConnected(): Promise<boolean> {
@@ -139,6 +161,10 @@ export class CodeCatalystBuilderIdState extends BaseBuilderIdState {
139161
protected override _startBuilderIdSetup(): Promise<void> {
140162
return client.startCodeCatalystBuilderIdSetup()
141163
}
164+
165+
override showNodeInView(): Promise<void> {
166+
return client.showCodeCatalystNode()
167+
}
142168
}
143169
</script>
144170
<style>

src/auth/ui/vue/authForms/manageCredentials.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
<div>
44
<FormTitle :isConnected="isConnected">IAM Credentials</FormTitle>
55

6+
<div class="form-section">
7+
<button v-if="isConnected" v-on:click="showResourceExplorer">Open Resource Explorer</button>
8+
</div>
9+
610
<div v-if="isConnected" class="form-section" v-on:click="toggleShowForm()" id="collapsible">
711
<div :class="collapsibleClass"></div>
812
<div>Add another profile</div>
@@ -135,7 +139,7 @@ export default defineComponent({
135139
async updateConnectedStatus() {
136140
return this.state.isAuthConnected().then(isConnected => {
137141
this.isConnected = isConnected
138-
this.emitAuthConnectionUpdated('CREDENTIALS')
142+
this.emitAuthConnectionUpdated('credentials')
139143
})
140144
},
141145
async submitData() {
@@ -169,6 +173,9 @@ export default defineComponent({
169173
editCredentialsFile() {
170174
client.editCredentialsFile()
171175
},
176+
showResourceExplorer() {
177+
client.showResourceExplorer()
178+
},
172179
},
173180
watch: {
174181
'data.profileName'(newVal) {

src/auth/ui/vue/authForms/manageIdentityCenter.vue

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
<div class="form-section">
4343
<div v-on:click="signout()" style="cursor: pointer; color: #75beff">Sign out</div>
4444
</div>
45+
46+
<div class="form-section">
47+
<button v-on:click="showView()">Open {{ authName }} in Toolkit</button>
48+
</div>
4549
</div>
4650
</div>
4751
</div>
@@ -85,6 +89,7 @@ export default defineComponent({
8589
stage: 'START' as IdentityCenterStage,
8690
8791
canShowAll: false,
92+
authName: this.state.name,
8893
}
8994
},
9095
@@ -122,6 +127,9 @@ export default defineComponent({
122127
123128
this.canSubmit = await this.state.canSubmit()
124129
},
130+
showView() {
131+
this.state.showView()
132+
},
125133
},
126134
watch: {
127135
'data.startUrl'(value: string) {
@@ -151,8 +159,10 @@ abstract class BaseIdentityCenterState implements AuthStatus {
151159
}
152160
153161
abstract get id(): AuthFormId
162+
abstract get name(): string
154163
protected abstract _startIdentityCenterSetup(): Promise<void>
155164
abstract isAuthConnected(): Promise<boolean>
165+
abstract showView(): Promise<void>
156166
157167
setValue(key: IdentityCenterKey, value: string) {
158168
this._data[key] = value
@@ -199,7 +209,11 @@ abstract class BaseIdentityCenterState implements AuthStatus {
199209
200210
export class CodeWhispererIdentityCenterState extends BaseIdentityCenterState {
201211
override get id(): AuthFormId {
202-
return 'IDENTITY_CENTER_CODE_WHISPERER'
212+
return 'identityCenterCodeWhisperer'
213+
}
214+
215+
override get name(): string {
216+
return 'CodeWhisperer'
203217
}
204218
205219
protected override async _startIdentityCenterSetup(): Promise<void> {
@@ -210,6 +224,10 @@ export class CodeWhispererIdentityCenterState extends BaseIdentityCenterState {
210224
override async isAuthConnected(): Promise<boolean> {
211225
return client.isCodeWhispererIdentityCenterConnected()
212226
}
227+
228+
override async showView(): Promise<void> {
229+
client.showCodeWhispererNode()
230+
}
213231
}
214232
</script>
215233
<style>

src/auth/ui/vue/authForms/shared.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import { AuthFormId } from './types'
88
* The state instance of all auth forms
99
*/
1010
const authFormsState: Readonly<Record<AuthFormId, any>> = {
11-
CREDENTIALS: new CredentialsState() as CredentialsState,
12-
BUILDER_ID_CODE_WHISPERER: new CodeWhispererBuilderIdState(),
13-
BUILDER_ID_CODE_CATALYST: new CodeCatalystBuilderIdState(),
14-
IDENTITY_CENTER_CODE_WHISPERER: new CodeWhispererIdentityCenterState(),
11+
credentials: new CredentialsState() as CredentialsState,
12+
builderIdCodeWhisperer: new CodeWhispererBuilderIdState(),
13+
builderIdCodeCatalyst: new CodeCatalystBuilderIdState(),
14+
identityCenterCodeWhisperer: new CodeWhispererIdentityCenterState(),
1515
} as const
1616
1717
export interface AuthStatus {

src/auth/ui/vue/authForms/types.ts

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

66
export type AuthFormId =
7-
| 'CREDENTIALS'
8-
| 'BUILDER_ID_CODE_WHISPERER'
9-
| 'BUILDER_ID_CODE_CATALYST'
10-
| 'IDENTITY_CENTER_CODE_WHISPERER'
7+
| 'credentials'
8+
| 'builderIdCodeWhisperer'
9+
| 'builderIdCodeCatalyst'
10+
| 'identityCenterCodeWhisperer'

src/auth/ui/vue/root.vue

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export default defineComponent({
9898
}
9999
},
100100
async created() {
101+
await this.selectInitialService()
101102
await this.updateServiceConnections()
102103
103104
// This handles the case where non-webview auth setup is used.
@@ -111,6 +112,9 @@ export default defineComponent({
111112
// this forced rerender will display the new state
112113
this.rerenderSelectedContentWindow()
113114
})
115+
client.onDidSelectService((id: ServiceItemId) => {
116+
this.selectService(id)
117+
})
114118
},
115119
mounted() {
116120
window.addEventListener('resize', this.updateWindowWidth)
@@ -157,6 +161,10 @@ export default defineComponent({
157161
serviceItemsState.toggleSelected(id)
158162
this.renderItems()
159163
},
164+
selectService(id: ServiceItemId) {
165+
serviceItemsState.select(id)
166+
this.renderItems()
167+
},
160168
/**
161169
* Builds a unique key for a service item to optimize re-rendering.
162170
*
@@ -189,14 +197,14 @@ export default defineComponent({
189197
},
190198
async updateServiceConnections() {
191199
return Promise.all([
192-
this.serviceItemsAuthStatus.RESOURCE_EXPLORER.isAuthConnected().then(isConnected => {
193-
this.updateServiceLock('RESOURCE_EXPLORER', isConnected)
200+
this.serviceItemsAuthStatus.resourceExplorer.isAuthConnected().then(isConnected => {
201+
this.updateServiceLock('resourceExplorer', isConnected)
194202
}),
195-
this.serviceItemsAuthStatus.CODE_WHISPERER.isAuthConnected().then(isConnected => {
196-
this.updateServiceLock('CODE_WHISPERER', isConnected)
203+
this.serviceItemsAuthStatus.codewhisperer.isAuthConnected().then(isConnected => {
204+
this.updateServiceLock('codewhisperer', isConnected)
197205
}),
198-
this.serviceItemsAuthStatus.CODE_CATALYST.isAuthConnected().then(isConnected => {
199-
this.updateServiceLock('CODE_CATALYST', isConnected)
206+
this.serviceItemsAuthStatus.codecatalyst.isAuthConnected().then(isConnected => {
207+
this.updateServiceLock('codecatalyst', isConnected)
200208
}),
201209
]).then(() => this.renderItems())
202210
},
@@ -207,6 +215,12 @@ export default defineComponent({
207215
// Arbitrarily toggles value between 0 and 1
208216
this.rerenderContentWindowKey = this.rerenderContentWindowKey === 0 ? 1 : 0
209217
},
218+
async selectInitialService() {
219+
const initialService = await client.getInitialService()
220+
if (initialService) {
221+
this.selectService(initialService)
222+
}
223+
},
210224
},
211225
})
212226
</script>

0 commit comments

Comments
 (0)