[extension] Problem panel

This commit is contained in:
orosmatthew 2023-05-07 11:01:27 -04:00
parent 5d48bd0b37
commit 234ce83d9d
7 changed files with 154 additions and 12 deletions

View File

@ -1,6 +1,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { getNonce } from './getNonce'; import { getNonce } from './getNonce';
import { cloneAndOpenRepo } from './extension'; import { cloneAndOpenRepo } from './extension';
import { BWPanel } from './problemPanel';
export class SidebarProvider implements vscode.WebviewViewProvider { export class SidebarProvider implements vscode.WebviewViewProvider {
_view?: vscode.WebviewView; _view?: vscode.WebviewView;
@ -24,6 +25,12 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
webviewView.webview.onDidReceiveMessage(async (data) => { webviewView.webview.onDidReceiveMessage(async (data) => {
switch (data.type) { switch (data.type) {
case 'onTestAndSubmit': {
if (this._context) {
BWPanel.createOrShow(this._context?.extensionUri, this._context);
}
break;
}
case 'onStartup': { case 'onStartup': {
const token: string | undefined = this._context?.globalState.get('token'); const token: string | undefined = this._context?.globalState.get('token');
if (token) { if (token) {

View File

@ -2,6 +2,7 @@ import * as vscode from 'vscode';
import { SidebarProvider } from './SidebarProvider'; import { SidebarProvider } from './SidebarProvider';
import * as child_process from 'child_process'; import * as child_process from 'child_process';
import * as fs from 'fs-extra'; import * as fs from 'fs-extra';
import { BWPanel } from './problemPanel';
interface BWContestSettings { interface BWContestSettings {
repoBaseUrl: string; repoBaseUrl: string;
@ -42,7 +43,9 @@ export async function cloneAndOpenRepo(contestId: number, teamId: number) {
fs.mkdirSync(`${currentSettings.repoClonePath}/BWContest/${contestId.toString()}`); fs.mkdirSync(`${currentSettings.repoClonePath}/BWContest/${contestId.toString()}`);
} }
const clonedRepoPath = `${currentSettings.repoClonePath}/BWContest/${contestId.toString()}/${repoName}`; const clonedRepoPath = `${
currentSettings.repoClonePath
}/BWContest/${contestId.toString()}/${repoName}`;
if (fs.existsSync(clonedRepoPath)) { if (fs.existsSync(clonedRepoPath)) {
const confirm = await vscode.window.showWarningMessage( const confirm = await vscode.window.showWarningMessage(
@ -88,7 +91,11 @@ export function activate(context: vscode.ExtensionContext) {
vscode.window.registerWebviewViewProvider('bwcontest-sidebar', sidebarProvider) vscode.window.registerWebviewViewProvider('bwcontest-sidebar', sidebarProvider)
); );
context.subscriptions.push(vscode.commands.registerCommand('bwcontest.helloWorld', () => {})); context.subscriptions.push(
vscode.commands.registerCommand('bwcontest.helloWorld', () => {
BWPanel.createOrShow(context.extensionUri, context);
})
);
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand('bwcontest.askQuestion', async () => { vscode.commands.registerCommand('bwcontest.askQuestion', async () => {

View File

@ -12,8 +12,10 @@ export class BWPanel {
private readonly _panel: vscode.WebviewPanel; private readonly _panel: vscode.WebviewPanel;
private readonly _extensionUri: vscode.Uri; private readonly _extensionUri: vscode.Uri;
private _disposables: vscode.Disposable[] = []; private _disposables: vscode.Disposable[] = [];
private static _context?: vscode.ExtensionContext;
public static createOrShow(extensionUri: vscode.Uri) { public static createOrShow(extensionUri: vscode.Uri, context: vscode.ExtensionContext) {
this._context = context;
const column = vscode.window.activeTextEditor const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn ? vscode.window.activeTextEditor.viewColumn
: undefined; : undefined;
@ -99,6 +101,17 @@ export class BWPanel {
this._panel.webview.html = this._getHtmlForWebview(webview); this._panel.webview.html = this._getHtmlForWebview(webview);
webview.onDidReceiveMessage(async (data) => { webview.onDidReceiveMessage(async (data) => {
switch (data.type) { switch (data.type) {
case 'onStartup': {
const token: string | undefined = BWPanel._context?.globalState.get('token');
if (token) {
this._panel.webview.postMessage({
type: 'onSession',
value: token
});
}
break;
}
case 'onInfo': { case 'onInfo': {
if (!data.value) { if (!data.value) {
return; return;
@ -125,7 +138,7 @@ export class BWPanel {
private _getHtmlForWebview(webview: vscode.Webview) { private _getHtmlForWebview(webview: vscode.Webview) {
// // And the uri we use to load this script in the webview // // And the uri we use to load this script in the webview
const scriptUri = webview.asWebviewUri( const scriptUri = webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'HelloWorld.js') vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'problemPanel.js')
); );
// Uri to load styles into webview // Uri to load styles into webview
@ -135,9 +148,9 @@ export class BWPanel {
const stylesMainUri = webview.asWebviewUri( const stylesMainUri = webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css') vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css')
); );
// const cssUri = webview.asWebviewUri( const cssUri = webview.asWebviewUri(
// vscode.Uri.joinPath(this._extensionUri, 'out', 'compiled/swiper.css') vscode.Uri.joinPath(this._extensionUri, 'out/compiled', 'problemPanel.css')
// ); );
// // Use a nonce to only allow specific scripts to be run // // Use a nonce to only allow specific scripts to be run
const nonce = getNonce(); const nonce = getNonce();
@ -154,6 +167,10 @@ export class BWPanel {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${stylesResetUri}" rel="stylesheet"> <link href="${stylesResetUri}" rel="stylesheet">
<link href="${stylesMainUri}" rel="stylesheet"> <link href="${stylesMainUri}" rel="stylesheet">
<link href="${cssUri}" rel="stylesheet">
<script nonce="${nonce}">
const vscode = acquireVsCodeApi();
</script>
</head> </head>
<body> <body>
</body> </body>

View File

@ -1,4 +0,0 @@
<script lang="ts">
</script>
<h1>Test!</h1>

View File

@ -0,0 +1,110 @@
<script lang="ts">
import { onMount } from "svelte";
function postMessage(message: any) {
vscode.postMessage(message);
}
type ProblemData = {
id: number,
name: string,
sampleInput: string,
sampleOutput: string
}[];
let activeProblem: ProblemData[0];
let sessionToken: string | undefined;
let problemData: ProblemData | undefined;
let sampleInputText: HTMLTextAreaElement;
$: if (problemData && problemData.length !== 0) {
let first = problemData.at(0);
if (first) {
activeProblem = first;
}
};
function resetInput() {
sampleInputText.value = activeProblem.sampleInput;
}
async function fetchProblemData() {
if (sessionToken) {
const res = await fetch(`http://localhost:5173/api/contest/${sessionToken}`);
const data = await res.json();
if (data.success === true) {
problemData = data.problems as ProblemData;
}
}
}
window.addEventListener("message", async (event) => {
const message = (event as MessageEvent).data;
if (message.type === "onSession") {
if (message.value !== "") {
sessionToken = message.value;
await fetchProblemData();
}
}
})
onMount(() => {
postMessage({type: "onStartup"});
})
</script>
<h1>Test & Submit Problems</h1>
{#if problemData}
<div class="tab-container">
{#each problemData as problem}
<button on:click={() => {
activeProblem = problem;
}} id={`problem_${problem.id}`} type="button" class={"tab " + (activeProblem.id == problem.id ? "active" : "")}>{problem.name}</button>
{/each}
</div>
{/if}
{#if activeProblem}
<h2>{activeProblem.name}</h2>
<div style="display:flex">
<div style="flex:1; margin-right:20px">
<h3>Sample Input (You can edit this!)</h3>
<textarea bind:this={sampleInputText}>{activeProblem.sampleInput}</textarea>
<button style="margin-top:5px" on:click={resetInput} type="button">Reset Input</button>
</div>
<div style="flex:1">
<h3>Output</h3>
<textarea disabled>{activeProblem.sampleOutput}</textarea>
</div>
</div>
{/if}
<style>
textarea {
resize: vertical;
height: 250px;
}
.tab-container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
height: 30px;
margin-bottom: 10px;
}
.tab {
flex: 1;
border: none;
cursor: pointer;
text-align: center;
}
.tab.active {
background-color: rgb(95, 103, 118);
}
</style>

View File

@ -86,6 +86,10 @@
} }
}) })
function onTestAndSubmit() {
postMessage({type: 'onTestAndSubmit'});
}
onMount(() => { onMount(() => {
postMessage({type: "onStartup"}); postMessage({type: "onStartup"});
}) })
@ -107,5 +111,6 @@
<p>TeamID: {teamData.teamId}</p> <p>TeamID: {teamData.teamId}</p>
<p>ContestID: {teamData.contestId}</p> <p>ContestID: {teamData.contestId}</p>
<button on:click={onClone}>Clone and Open Repo</button> <button on:click={onClone}>Clone and Open Repo</button>
<button on:click={onTestAndSubmit}>Test & Submit</button>
{/if} {/if}
{/if} {/if}

View File

@ -1,4 +1,4 @@
import App from '../components/HelloWorld.svelte'; import App from '../components/ProblemPanel.svelte';
const app = new App({ const app = new App({
target: document.body target: document.body