Skip to content

Commit ab6d79a

Browse files
committed
Merge branch 'main' of github.com:source-academy/vscode into chapter-selection
2 parents f0ce794 + e87a9f4 commit ab6d79a

File tree

13 files changed

+214
-106
lines changed

13 files changed

+214
-106
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,16 @@ After installing the extension,
4141
1. Click on the newly-added Source Academy icon on the left sidebar.
4242
2. Launch the Source Academy panel.
4343

44-
<img src="./docs/images/launch-panel-from-sidebar.png" width="600">
44+
<img src="./docs/images/launch-panel-from-sidebar.png" width="600">
4545

46-
Alternatively, use the `Source Academy: Show the Source Academy Panel` command.
46+
Alternatively, use the `Source Academy: Show the Source Academy Panel` command.
4747

48-
Once the panel loads, you'll be prompted to log in. Afterwards, begin coding by opening any assessment.
48+
3. Choose a login method and authenticate in your browser.
49+
50+
- When prompted, click **Open** to proceed to the external website.
51+
- After login, click **Open** again to allow the extension to open the URI. Optionally, check `Do not ask me again for this extension`.
52+
53+
4. You may now begin coding by opening any assessment.
4954

5055
### Changing the frontend
5156

package.json

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "source-academy",
3-
"version": "0.3.1",
3+
"version": "0.4.2",
44
"publisher": "source-academy",
55
"license": "Apache-2.0",
66
"displayName": "Source Academy",
@@ -26,7 +26,8 @@
2626
},
2727
{
2828
"command": "source-academy.show-panel",
29-
"title": "Source Academy: Show the Source Academy panel"
29+
"title": "Source Academy: Show the Source Academy panel",
30+
"icon": "$(rocket)"
3031
},
3132
{
3233
"command": "source-academy.eval-editor",
@@ -38,9 +39,14 @@
3839
"properties": {
3940
"source-academy.frontendBaseUrl": {
4041
"type": "string",
41-
"default": "https://frontend.cloud.heyzec.dedyn.io",
42+
"default": "https://sourceacademy.nus.edu.sg",
4243
"description": "URL to the Source Academy frontend"
4344
},
45+
"source-academy.backendBaseUrl": {
46+
"type": "string",
47+
"default": "https://api.sourceacademy.nus.edu.sg",
48+
"description": "URL to the Source Academy backend (only needed for SAML logins)"
49+
},
4450
"source-academy.workspaceFolder": {
4551
"type": "string",
4652
"default": ".sourceacademy",
@@ -74,11 +80,20 @@
7480
"key": "shift+enter"
7581
}
7682
],
83+
"menus": {
84+
"view/title": [
85+
{
86+
"command": "source-academy.show-panel",
87+
"when": "view == assessments",
88+
"group": "navigation"
89+
}
90+
]
91+
},
7792
"views": {
7893
"source-academy": [
7994
{
8095
"id": "assessments",
81-
"name": "Assessments",
96+
"name": "",
8297
"icon": "assets/icon.svg",
8398
"contextualTitle": "Source Academy"
8499
}

scripts/lsp.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ async function main() {
2222

2323
async function downloadLsp() {
2424
const outputFolder = getOutputDir();
25-
const version = "0.1.9";
25+
const version = "0.1.10";
2626
const lspFilename = "source-lsp.js";
2727
const url = `https://github.com/source-academy/source-lsp/releases/download/v${version}/${lspFilename}`;
2828
// const url = `https://github.com/source-academy/source-lsp/releases/latest/download/${lspFilename}`;

src/commands/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const EXTENSION_ID = "source-academy";
1212
*/
1313
const commands = (context: vscode.ExtensionContext) => ({
1414
pick: () => runLanguagePicker(context),
15-
"show-panel": (route?: string) => showPanel(context, route),
15+
"show-panel": (route?: string, altUrl?: string) =>
16+
showPanel(context, route, altUrl),
1617
"eval-editor": () => evalEditor(context),
1718
navigate: (route: string) => navigate(context, route),
1819
});

src/commands/showPanel.tsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,36 @@ let messageHandler = MessageHandler.getInstance();
1616
export async function showPanel(
1717
context: vscode.ExtensionContext,
1818
route?: string,
19+
altUrl?: string,
1920
) {
2021
let language: string | undefined = context.workspaceState.get("language");
2122
if (!language) {
2223
language = LANGUAGES.SOURCE_1;
2324
}
2425

25-
// Get a reference to the active editor (before the focus is switched to our newly created webview)
26-
// firstEditor = vscode.window.activeTextEditor!;
27-
28-
messageHandler.panel = vscode.window.createWebviewPanel(
29-
"source-academy-panel",
30-
"Source Academy",
31-
vscode.ViewColumn.Beside,
32-
{
33-
enableScripts: true, // Enable scripts in the webview
34-
retainContextWhenHidden: true,
35-
},
36-
);
26+
// Don't recreate the panel it already exists. There will only be one panel at anytime.
27+
if (!messageHandler.panel) {
28+
messageHandler.panel = vscode.window.createWebviewPanel(
29+
"source-academy-panel",
30+
"Source Academy",
31+
vscode.ViewColumn.Beside,
32+
{
33+
enableScripts: true, // Enable scripts in w the webview
34+
retainContextWhenHidden: true,
35+
},
36+
);
3737

38-
messageHandler.panel.webview.onDidReceiveMessage(
39-
(message: MessageType) => messageHandler.handleMessage(context, message),
40-
undefined,
41-
context.subscriptions,
42-
);
38+
messageHandler.panel.webview.onDidReceiveMessage(
39+
(message: MessageType) => messageHandler.handleMessage(context, message),
40+
undefined,
41+
context.subscriptions,
42+
);
43+
}
4344

44-
const iframeUrl = new URL(route ?? "/playground", config.frontendBaseUrl)
45-
.href;
45+
const iframeUrl =
46+
altUrl ?? new URL(route ?? "/playground", config.frontendBaseUrl).href;
4647

48+
// equivalent to panel.webview.html = ...
4749
setWebviewContent(
4850
messageHandler.panel,
4951
context,

src/extension.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,32 @@ export function activate(context: vscode.ExtensionContext) {
5151
"*.js": "source",
5252
});
5353
}
54+
55+
vscode.window.registerUriHandler({
56+
handleUri(uri: vscode.Uri) {
57+
const searchParams = new URLSearchParams(uri.query);
58+
59+
const code = searchParams.get("code");
60+
// The following params are available conditionally based on provider
61+
const clientRequestId = searchParams.get("client-request-id"); // OAuth (NUS's IdP)
62+
const provider = searchParams.get("provider"); // SAML
63+
64+
let route, url;
65+
if (clientRequestId) {
66+
// OAuth
67+
route = `/login/vscode_callback?code=${code}&client-request-id=${clientRequestId}`;
68+
url = null;
69+
} else if (provider) {
70+
// SAML
71+
route = null;
72+
// TODO: Let the frontend handle the contacting of backend, instead of us.
73+
// Then, remove backendBaseUrl from schema and altUrl from showPanel
74+
url = `${config.backendBaseUrl}/v2/auth/exchange?code=${code}&provider=${provider}`;
75+
}
76+
77+
vscode.commands.executeCommand("source-academy.show-panel", route, url);
78+
},
79+
});
5480
}
5581

5682
// This method is called when your extension is deactivated

src/treeview/index.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export class AssessmentsSidebarProvider
3333
}
3434

3535
getChildren(element?: BaseTreeItem): Thenable<BaseTreeItem[]> {
36+
// Synthetic root item that launches the Source Academy panel.
37+
const launchItem = new PlaygroundItem();
38+
3639
// @ts-ignore
3740
const assessmentOverviews: VscAssessmentOverview[] =
3841
this.context.globalState.get("assessmentOverviews");
@@ -44,14 +47,18 @@ export class AssessmentsSidebarProvider
4447
const assessmentTypes = [
4548
...new Set(assessmentOverviews.map((ao) => ao.type)),
4649
];
47-
return Promise.resolve(
48-
assessmentTypes.map((at) => new AssessmentFolder(at)),
49-
);
50+
const folders = assessmentTypes.map((at) => new AssessmentFolder(at));
51+
52+
return Promise.resolve([launchItem, ...folders]);
5053
}
5154

5255
if (element && element.type === "AssessmentFolder") {
5356
const elem = element as AssessmentFolder;
5457

58+
if (!assessmentOverviews) {
59+
return Promise.resolve([]);
60+
}
61+
5562
return Promise.resolve(
5663
assessmentOverviews
5764
.filter((ao) => ao.type == elem.assessmentType)
@@ -84,6 +91,21 @@ class BaseTreeItem extends vscode.TreeItem {
8491
};
8592
}
8693

94+
/**
95+
* Synthetic tree item that always appears at the top-level of the view.
96+
*/
97+
class PlaygroundItem extends BaseTreeItem {
98+
constructor() {
99+
super("Playground", vscode.TreeItemCollapsibleState.None);
100+
this.type = "LaunchItem";
101+
this.command = {
102+
title: "Playground",
103+
command: "source-academy.navigate",
104+
arguments: ["/playground"],
105+
};
106+
}
107+
}
108+
87109
class AssessmentFolder extends BaseTreeItem {
88110
constructor(public readonly assessmentType: string) {
89111
super(assessmentType, vscode.TreeItemCollapsibleState.Collapsed);

src/utils/config/schema.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import { ConfigSchemaUnion } from "./types";
33
export default {
44
frontendBaseUrl: {
55
type: "string",
6-
default: "https://frontend.cloud.heyzec.dedyn.io",
6+
default: "https://sourceacademy.nus.edu.sg",
7+
},
8+
// TODO: Remove this config in the future. See the login URI handler for details.
9+
backendBaseUrl: {
10+
type: "string",
11+
default: "https://api.sourceacademy.nus.edu.sg",
712
},
813
workspaceFolder: {
914
type: "string",

0 commit comments

Comments
 (0)