Skip to content

Commit 74f20e2

Browse files
authWebview: Setup initial Auth Add Connections webview (#3327)
Problem: We want to create a webview for Auth setup Solution: This does the following: - Creates a vscode command which can be executed in the command palette to open the webview - Sets up the initial code for a webview to be shown Signed-off-by: Nikolas Komonen <[email protected]>
1 parent b3da1fb commit 74f20e2

File tree

8 files changed

+206
-1
lines changed

8 files changed

+206
-1
lines changed

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,10 @@
10991099
"command": "aws.auth.help",
11001100
"when": "false"
11011101
},
1102+
{
1103+
"command": "aws.auth.showConnectionsPage",
1104+
"when": "aws.isDevMode"
1105+
},
11021106
{
11031107
"command": "aws.dev.openMenu",
11041108
"when": "aws.isDevMode || isCloud9"
@@ -1983,6 +1987,12 @@
19831987
"title": "%AWS.command.auth.addConnection%",
19841988
"category": "%AWS.title%"
19851989
},
1990+
{
1991+
"command": "aws.auth.showConnectionsPage",
1992+
"title": "%AWS.command.auth.showConnectionsPage%",
1993+
"category": "%AWS.title%",
1994+
"enablement": "aws.isDevMode"
1995+
},
19861996
{
19871997
"command": "aws.auth.switchConnections",
19881998
"title": "%AWS.command.auth.switchConnections%",

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +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",
7980
"AWS.command.auth.switchConnections": "Switch Connections",
8081
"AWS.command.auth.signout": "Sign out",
8182
"AWS.command.github": "View Source on GitHub",

src/credentials/activation.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { Settings } from '../shared/settings'
99
import { Auth } from './auth'
1010
import { LoginManager } from './loginManager'
1111
import { fromString } from './providers/credentials'
12+
import { AuthCommandBackend, AuthCommandDeclarations } from './commands'
13+
import { registerCommandsWithVSCode } from '../shared/vscode/commands2'
1214

1315
export async function initialize(
1416
extensionContext: vscode.ExtensionContext,
@@ -24,4 +26,12 @@ export async function initialize(
2426
loginManager.logout()
2527
}
2628
})
29+
30+
// TODO: To enable this in prod we need to remove the 'when' clause
31+
// for: '"command": "aws.auth.showConnectionsPage"' in package.json
32+
registerCommandsWithVSCode(
33+
extensionContext,
34+
new AuthCommandDeclarations(),
35+
new AuthCommandBackend(extensionContext)
36+
)
2737
}

src/credentials/commands.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*!
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { CommandDeclarations, Commands } from '../shared/vscode/commands2'
7+
import * as vscode from 'vscode'
8+
import { showAuthWebview } from './vue/show'
9+
10+
/**
11+
* The methods with backend logic for the Auth commands.
12+
*/
13+
export class AuthCommandBackend {
14+
constructor(private readonly extContext: vscode.ExtensionContext) {}
15+
16+
public async showConnectionsPage() {
17+
await showAuthWebview(this.extContext)
18+
}
19+
}
20+
21+
/**
22+
* Declared commands related to Authentication in the toolkit.
23+
*/
24+
export class AuthCommandDeclarations implements CommandDeclarations<AuthCommandBackend> {
25+
public readonly declared = {
26+
showConnectionsPage: Commands.from(AuthCommandBackend).declareShowConnectionsPage({
27+
id: 'aws.auth.showConnectionsPage',
28+
}),
29+
} as const
30+
}

src/credentials/vue/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*!
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* This module is run within the webview, and will mount the Vue app.
6+
*/
7+
8+
import { createApp } from 'vue'
9+
import component from './root.vue'
10+
11+
const create = () => createApp(component)
12+
const app = create()
13+
14+
app.mount('#vue-app')
15+
window.addEventListener('remount', () => {
16+
app.unmount()
17+
create().mount('#vue-app')
18+
})

src/credentials/vue/root.vue

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<template>
2+
<div class="flex-container" style="display: flex">
3+
<div id="left-column">I am left column</div>
4+
<div id="right-column">I am right column</div>
5+
</div>
6+
</template>
7+
8+
<script lang="ts">
9+
import { defineComponent } from 'vue'
10+
11+
export default defineComponent({
12+
name: 'MyComponent',
13+
})
14+
</script>
15+
16+
<style>
17+
/** By default */
18+
.flex-container {
19+
display: flex;
20+
flex-direction: row;
21+
width: 1200px;
22+
}
23+
24+
/* Makes webview responsive and changes to single column when necessary */
25+
@media (max-width: 1200px) {
26+
.flex-container {
27+
flex-direction: column;
28+
29+
color: red;
30+
}
31+
}
32+
33+
#left-column {
34+
flex-grow: 1;
35+
max-width: 40%;
36+
37+
/* This can be deleted, for development purposes */
38+
background-color: yellow;
39+
color: black;
40+
height: 200px;
41+
}
42+
43+
#right-column {
44+
flex-grow: 1;
45+
max-width: 60%;
46+
47+
/* This can be deleted, for development purposes */
48+
background-color: aqua;
49+
color: black;
50+
height: 200px;
51+
}
52+
</style>

src/credentials/vue/show.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*!
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* This module sets up the necessary components
6+
* for the webview to be shown.
7+
*/
8+
9+
import { getIdeProperties, isCloud9 } from '../../shared/extensionUtilities'
10+
import { VueWebview } from '../../webviews/main'
11+
import * as vscode from 'vscode'
12+
13+
class AuthWebview extends VueWebview {
14+
public override id: string = 'authWebview'
15+
public override source: string = 'src/credentials/vue/index.js'
16+
}
17+
18+
const Panel = VueWebview.compilePanel(AuthWebview)
19+
let activePanel: InstanceType<typeof Panel> | undefined
20+
let subscriptions: vscode.Disposable[] | undefined
21+
let submitPromise: Promise<void> | undefined
22+
23+
export async function showAuthWebview(ctx: vscode.ExtensionContext): Promise<void> {
24+
submitPromise ??= new Promise<void>((resolve, reject) => {
25+
activePanel ??= new Panel(ctx)
26+
})
27+
28+
const webview = await activePanel!.show({
29+
title: `Add Connection to ${getIdeProperties().company}`,
30+
viewColumn: isCloud9() ? vscode.ViewColumn.One : vscode.ViewColumn.Active,
31+
})
32+
33+
if (!subscriptions) {
34+
subscriptions = [
35+
webview.onDidDispose(() => {
36+
vscode.Disposable.from(...(subscriptions ?? [])).dispose()
37+
activePanel = undefined
38+
subscriptions = undefined
39+
submitPromise = undefined
40+
}),
41+
]
42+
}
43+
44+
return submitPromise
45+
}

src/shared/vscode/commands2.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,53 @@ export interface Command<T extends Callback = Callback> {
4343
execute(...parameters: Parameters<T>): Promise<ReturnType<T> | undefined>
4444
}
4545

46+
/**
47+
* Represents a command that has been registered with VS Code, meaning
48+
* it can be executed with the `executeCommand` API.
49+
*/
4650
interface RegisteredCommand<T extends Callback = Callback> extends Command<T> {
4751
dispose(): void
4852
}
4953

50-
interface DeclaredCommand<T extends Callback = Callback, U extends any[] = any> extends Command<T> {
54+
/**
55+
* Represents a command that has been declared but not yet registered with
56+
* VS Code
57+
*
58+
* This is a "lazy" command that is only registered when it is actually used.
59+
*/
60+
interface DeclaredCommand<T extends Callback = Callback, U extends any[] = any[]> extends Command<T> {
5161
register(...dependencies: U): RegisteredCommand<T>
5262
}
5363

64+
/**
65+
* Classes that have "declared" commands which wrap the underlying
66+
* logic provided by 'T'.
67+
*
68+
* These declared commands can then be used to do things like register
69+
* it as a VS Code command, or to build a tree node that uses the command.
70+
*
71+
* @param T The class that declares the commands
72+
*/
73+
export interface CommandDeclarations<T> {
74+
readonly declared: { [K in FunctionKeys<T>]: DeclaredCommand<Functions<T>[K], [T]> }
75+
}
76+
77+
/**
78+
* Using the given inputs will register the given commands with VS Code.
79+
*
80+
* @param declarations Has the mapping of command names to the backend logic
81+
* @param backend The backend logic of the commands
82+
*/
83+
export function registerCommandsWithVSCode<T>(
84+
extContext: vscode.ExtensionContext,
85+
declarations: CommandDeclarations<T>,
86+
backend: T
87+
): void {
88+
extContext.subscriptions.push(
89+
...Object.values<DeclaredCommand>(declarations.declared).map(c => c.register(backend))
90+
)
91+
}
92+
5493
/**
5594
* Minimal wrapper around VS Code's `commands` API to give structure around commands registered
5695
* and consumed by the extension.

0 commit comments

Comments
 (0)