Commit d8ec8044 authored by Ayush's avatar Ayush

Add compile components

parent 2ce9ffeb
...@@ -18,6 +18,7 @@ const routes: Routes = [ ...@@ -18,6 +18,7 @@ const routes: Routes = [
{path: 'files', component: FileComponent, canActivate: [AuthGuard]}, {path: 'files', component: FileComponent, canActivate: [AuthGuard]},
{path: 'login', component: LoginComponent}, {path: 'login', component: LoginComponent},
{path: 'register', component: RegisterComponent}, {path: 'register', component: RegisterComponent},
{path: 'arena', redirectTo: '/arena/file/new'},
{path: '**', redirectTo: '/home'}, {path: '**', redirectTo: '/home'},
]; ];
......
...@@ -9,10 +9,10 @@ import {HeaderComponent} from './header/header.component'; ...@@ -9,10 +9,10 @@ import {HeaderComponent} from './header/header.component';
import {ApiService} from './api.service'; import {ApiService} from './api.service';
import {IdeCompileComponent} from './ide-compile/ide-compile.component'; import {IdeCompileComponent} from './ide-compile/ide-compile.component';
import {InputComponent} from './input/input.component'; import {InputComponent} from './input/input.component';
import {TestcaseStatusComponent} from './testcase-status/testcase-status.component';
import {SaveFileComponent} from './save-file/save-file.component'; import {SaveFileComponent} from './save-file/save-file.component';
import {FileComponent} from './file/file.component'; import {FileComponent} from './file/file.component';
import {FileService} from './file.service'; import {FileService} from './file.service';
import { SubmitTryCodeComponent } from './submit-try-code/submit-try-code.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -21,9 +21,9 @@ import {FileService} from './file.service'; ...@@ -21,9 +21,9 @@ import {FileService} from './file.service';
routerComponents, routerComponents,
IdeCompileComponent, IdeCompileComponent,
InputComponent, InputComponent,
TestcaseStatusComponent,
SaveFileComponent, SaveFileComponent,
FileComponent FileComponent,
SubmitTryCodeComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
......
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
</div> </div>
<div id="toggle-lang">C++</div> <div id="toggle-lang">C++</div>
<div id="attempt"> <div id="attempt">
<button id="input">Custom Input</button> <button id="input" (click)="inputField.setState(true)">Custom Input</button>
<button id="try">Try Code</button> <button id="try" (click)="tryCode(0)" [class.disabled]="compilationError">{{compilationError ? 'Error' : 'Try Code'}}</button>
<button id="submit">Submit Code</button> <button id="submit" (click)="tryCode(1)" [class.disabled]="compilationError">{{compilationError ? 'Encountered' : 'Submit Code'}}</button>
</div> </div>
<label for="editor"></label> <label for="editor"></label>
<textarea id="editor" name="editor"></textarea> <textarea id="editor" name="editor"></textarea>
</div> </div>
<app-input></app-input> <app-input (valueEmit)="customInput = $event"></app-input>
<app-submit-try-code [problem]="problem"></app-submit-try-code>
...@@ -44,6 +44,17 @@ ...@@ -44,6 +44,17 @@
background: var(--color); background: var(--color);
color: var(--bgcolor); color: var(--bgcolor);
} }
&:hover {
background: var(--color);
color: var(--bgcolor);
}
&.disabled:hover {
cursor: default;
background: transparent;
color: #ddf;
}
} }
} }
} }
...@@ -56,6 +67,10 @@ label { ...@@ -56,6 +67,10 @@ label {
.container { .container {
padding: 20px 0; padding: 20px 0;
} }
#attempt, #toggle-lang {
right: 4px !important;
}
} }
@media screen and (max-width: 900px) { @media screen and (max-width: 900px) {
......
import {Component, OnInit} from '@angular/core'; import {Component, OnInit, ViewChild} from '@angular/core';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {Problem} from '../problem'; import {Problem} from '../problem';
import {ProblemService} from '../problem.service'; import {ProblemService} from '../problem.service';
import {File} from '../file';
import {ApiService} from '../api.service'; import {ApiService} from '../api.service';
import {InputComponent} from '../input/input.component';
import {SubmitTryCodeComponent} from '../submit-try-code/submit-try-code.component';
import {RunCodeService} from '../run-code.service';
declare const CodeMirror: any; declare const CodeMirror: any;
...@@ -16,9 +18,14 @@ export class ArenaComponent implements OnInit { ...@@ -16,9 +18,14 @@ export class ArenaComponent implements OnInit {
id: number; id: number;
problem: Problem; problem: Problem;
files: File[] = []; customInput = '';
compilationError = false;
constructor(public router: Router, private problemService: ProblemService, private apiService: ApiService) { @ViewChild(InputComponent) inputField: InputComponent;
@ViewChild(SubmitTryCodeComponent) submitField: SubmitTryCodeComponent;
constructor(public router: Router, private problemService: ProblemService, private apiService: ApiService,
private runCodeService: RunCodeService) {
} }
ngOnInit(): void { ngOnInit(): void {
...@@ -33,7 +40,7 @@ export class ArenaComponent implements OnInit { ...@@ -33,7 +40,7 @@ export class ArenaComponent implements OnInit {
matchBrackets: true matchBrackets: true
}); });
editor.setSize('auto', '70vh'); editor.setSize('auto', '70vh');
editor.setValue(this.problem.default_code[0]); editor.setValue(this.problem.code[0]);
Object.assign((document.getElementsByClassName('CodeMirror')[0] as HTMLTextAreaElement).style, { Object.assign((document.getElementsByClassName('CodeMirror')[0] as HTMLTextAreaElement).style, {
borderBottom: '1px solid #ddf', borderBottom: '1px solid #ddf',
padding: '20px', padding: '20px',
...@@ -51,21 +58,13 @@ export class ArenaComponent implements OnInit { ...@@ -51,21 +58,13 @@ export class ArenaComponent implements OnInit {
const th = this as HTMLDivElement; const th = this as HTMLDivElement;
activeLang = (activeLang + 1) % 3; activeLang = (activeLang + 1) % 3;
th.innerHTML = langs[activeLang]; th.innerHTML = langs[activeLang];
editor.setValue(problem.default_code[activeLang]); editor.setValue(problem.code[activeLang]);
editor.setOption('mode', langsMime[activeLang]); editor.setOption('mode', langsMime[activeLang]);
}; };
const filename = this.id.toString(10); editor.on('update', () => {
const username = JSON.parse(this.apiService.getToken()).username; this.problem.code[activeLang] = editor.getValue();
for (const ext of extensions) {
this.files.push({
username,
filename,
language: ext,
text: '',
path: '/'
}); });
}
} }
...@@ -76,4 +75,19 @@ export class ArenaComponent implements OnInit { ...@@ -76,4 +75,19 @@ export class ArenaComponent implements OnInit {
}); });
} }
tryCode(c): void {
this.runCodeService.compileProblemFile(this.problem)
.subscribe(data => {
if (document.getElementById('try').classList.contains('disabled')) {return; }
this.submitField.submitting = c;
this.submitField.reset();
this.submitField.isActive = true;
}, error => {
this.compilationError = true;
setTimeout(() => {
this.compilationError = false;
}, 3000);
});
}
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<a *ngIf="!loggedIn" routerLink="/register" routerLinkActive="active">Register</a> <a *ngIf="!loggedIn" routerLink="/register" routerLinkActive="active">Register</a>
<a *ngIf="!loggedIn" routerLink="/login" routerLinkActive="active">Login</a> <a *ngIf="!loggedIn" routerLink="/login" routerLinkActive="active">Login</a>
<a *ngIf="loggedIn" routerLink="/home" routerLinkActive="active">Home</a> <a *ngIf="loggedIn" routerLink="/home" routerLinkActive="active">Home</a>
<a *ngIf="loggedIn" routerLink="/arena/file/new" routerLinkActive="active">Arena</a> <a *ngIf="loggedIn" routerLink="/arena" routerLinkActive="active">Arena</a>
<a *ngIf="loggedIn" routerLink="/files" routerLinkActive="active">Files</a> <a *ngIf="loggedIn" routerLink="/files" routerLinkActive="active">Files</a>
<a *ngIf="loggedIn" routerLink="/user" routerLinkActive="active">User</a> <a *ngIf="loggedIn" routerLink="/user" routerLinkActive="active">User</a>
</nav> </nav>
#compile-popup { #compile-popup {
position: fixed; position: fixed;
top: calc(40vh - 100px); top: 50%;
width: 30vw; width: 30vw;
left: calc(35vw - 20px); left: calc(35vw - 20px);
border-bottom: 1px solid #ddf; border-bottom: 1px solid #ddf;
padding: 20px; padding: 20px;
background: #224; background: #224;
transform: scale(0); transform: translateY(-50%) scale(0);
opacity: 0; opacity: 0;
transition: all 0.25s; transition: all 0.25s;
z-index: 1000; z-index: 1000;
&.open { &.open {
transform: none; transform: translateY(-50%) scale(1);
opacity: 1; opacity: 1;
} }
} }
......
...@@ -13,5 +13,5 @@ ...@@ -13,5 +13,5 @@
<textarea id="editor" name="editor" value="{{inp}}"></textarea> <textarea id="editor" name="editor" value="{{inp}}"></textarea>
</div> </div>
<app-input (valueEmit)="updateInput($event)"></app-input> <app-input (valueEmit)="updateInput($event)"></app-input>
<app-ide-compile [resultVal]="runCodeService.result" [statusVal]="runCodeService.status"></app-ide-compile> <app-ide-compile [resultVal]="runCodeService.result" [statusVal]="runCodeService.runStatus"></app-ide-compile>
<app-save-file (savedFile)="isSaved = isUpToDate = true;" [file]="file"></app-save-file> <app-save-file (savedFile)="isSaved = isUpToDate = true;" [file]="file"></app-save-file>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
@media screen and (max-width: 800px) { @media screen and (max-width: 800px) {
.container { .container {
padding: 20px 0px; padding: 20px 0;
} }
#attempt { #attempt {
......
...@@ -106,6 +106,7 @@ int main() { ...@@ -106,6 +106,7 @@ int main() {
btn.innerHTML = 'Saved'; btn.innerHTML = 'Saved';
this.isUploading = false; this.isUploading = false;
this.isUpToDate = true; this.isUpToDate = true;
console.log(data);
}, error => { }, error => {
console.log(error); console.log(error);
this.isUploading = false; this.isUploading = false;
......
#input { #input {
position: fixed; position: fixed;
top: calc(40vh - 100px); top: 50%;
width: 30vw; width: 30vw;
left: calc(35vw - 20px); left: calc(35vw - 20px);
border-bottom: 1px solid #ddf; border-bottom: 1px solid #ddf;
padding: 20px; padding: 20px;
background: #224; background: #224;
transform: scale(0); transform: translateY(-50%) scale(0);
opacity: 0; opacity: 0;
transition: all 0.25s; transition: all 0.25s;
z-index: 1000; z-index: 1000;
&.open { &.open {
transform: none; transform: translateY(-50%) scale(1);
opacity: 1; opacity: 1;
} }
} }
......
...@@ -32,7 +32,7 @@ int main() { ...@@ -32,7 +32,7 @@ int main() {
return 0; return 0;
}</div> }</div>
Anyways, head on to the right section of the page to take the problem hands on, crack it ruthlessly and destroy the arrogance of the creator!`, Anyways, head on to the right section of the page to take the problem hands on, crack it ruthlessly and destroy the arrogance of the creator!`,
default_code: [`#include <iostream> code: [`#include <iostream>
using namespace std; using namespace std;
int main() { int main() {
...@@ -43,6 +43,7 @@ int main() { ...@@ -43,6 +43,7 @@ int main() {
System.out.println("Hello, World!"); System.out.println("Hello, World!");
} }
}`], }`],
n_testcases: [5, 15]
}); });
} }
......
...@@ -6,5 +6,6 @@ export interface Problem { ...@@ -6,5 +6,6 @@ export interface Problem {
n_attempts: number; n_attempts: number;
n_correct: number; n_correct: number;
problem_statement: string; problem_statement: string;
default_code: string[]; code: string[];
n_testcases: number[];
} }
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {Problem} from './problem';
import {Observable, of, throwError} from 'rxjs';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class RunCodeService { export class RunCodeService {
status = 'Compiling...'; runStatus = 'Compiling...';
result = 0; result = 0;
constructor() { constructor() {
...@@ -23,7 +25,7 @@ abcd ...@@ -23,7 +25,7 @@ abcd
let time = 0; let time = 0;
for (const status of statusArray) { for (const status of statusArray) {
setTimeout(() => { setTimeout(() => {
this.status = status; this.runStatus = status;
}, time); }, time);
time += 2000; time += 2000;
} }
...@@ -32,4 +34,13 @@ abcd ...@@ -32,4 +34,13 @@ abcd
this.result = 1; this.result = 1;
}, 6000); }, 6000);
} }
compileProblemFile(prob: Problem): Observable<string> {
if (Math.floor(Math.random() * 2) === 1) {return of('done'); }
else {return throwError('error'); }
}
tryTestcase(prob: Problem, index: number): Observable<boolean> {
return of(Math.floor(Math.random() * 2) === 1);
}
} }
#save-popup { #save-popup {
position: fixed; position: fixed;
top: calc(40vh - 100px); top: 50%;
width: 30vw; width: 30vw;
left: calc(35vw - 20px); left: calc(35vw - 20px);
border-bottom: 1px solid #ddf; border-bottom: 1px solid #ddf;
padding: 20px; padding: 20px;
background: #224; background: #224;
transform: scale(0); transform: translateY(-50%) scale(0);
opacity: 0; opacity: 0;
transition: all 0.25s; transition: all 0.25s;
z-index: 1000; z-index: 1000;
&.open { &.open {
transform: none; transform: translateY(-50%) scale(1);
opacity: 1; opacity: 1;
} }
} }
......
<div [class.open]="isActive" id="compile-cover"></div>
<div [class.open]="isActive" id="compile-popup">
<div id="testcase-grid">
<div *ngFor="let i of nts" class="testcase-status-div" [class.failed]="status[i] === -1" [class.successful]="status[i] === 1">Testcase {{i}}</div>
</div>
<div>
<button id="compile-done" (click)="isActive = false;">Done</button>
</div>
</div>
#compile-popup {
position: fixed;
top: 50%;
width: 50vw;
left: calc(25vw - 20px);
border-bottom: 1px solid #ddf;
padding: 20px;
background: #224;
transform: translateY(-50%) scale(0);
opacity: 0;
transition: all 0.25s;
z-index: 1000;
&.open {
transform: translateY(-50%) scale(1);
opacity: 1;
}
}
#compile-done {
float: right;
}
#compile-cover {
z-index: 999;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: none;
&.open {
display: block;
}
}
#testcase-grid {
display: grid;
grid-template-columns: auto auto auto;
}
.testcase-status-div {
margin: 10px;
padding: 10px;
display: flex;
justify-content: center;
color: #ddf;
border-bottom: 1px solid #ddf;
animation: blink 1s infinite;
&.failed {
animation: none;
border-color: #802;
background-color: #8028;
}
&.successful {
animation: none;
border-color:#082;
background-color: #0828;
}
}
@keyframes blink {
0%, 100% {
border-color: transparent;
}
50% {
border-color: #ddf;
}
}
import {ComponentFixture, TestBed} from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import {TestcaseStatusComponent} from './testcase-status.component'; import { SubmitTryCodeComponent } from './submit-try-code.component';
describe('TestcaseStatusComponent', () => { describe('SubmitTryCodeComponent', () => {
let component: TestcaseStatusComponent; let component: SubmitTryCodeComponent;
let fixture: ComponentFixture<TestcaseStatusComponent>; let fixture: ComponentFixture<SubmitTryCodeComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [TestcaseStatusComponent] declarations: [ SubmitTryCodeComponent ]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(TestcaseStatusComponent); fixture = TestBed.createComponent(SubmitTryCodeComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
......
import {Component, Input, OnInit} from '@angular/core';
import {Problem} from '../problem';
import {RunCodeService} from '../run-code.service';
@Component({
selector: 'app-submit-try-code',
templateUrl: './submit-try-code.component.html',
styleUrls: ['./submit-try-code.component.scss']
})
export class SubmitTryCodeComponent implements OnInit {
isActive = false;
nts: number[];
status: number[];
@Input() problem: Problem;
submitting = 0;
constructor(public runCodeService: RunCodeService) { }
ngOnInit(): void { }
reset(): void {
this.nts = Array(this.problem.n_testcases[this.submitting]).fill(1).map((x, i) => i);
this.status = Array(this.problem.n_testcases[this.submitting]).fill(0);
for (const i of this.nts) {
this.runCodeService.tryTestcase(this.problem, i)
.subscribe(ret => {
this.status[i] = ret ? 1 : -1;
});
}
}
}
import {Component, OnInit} from '@angular/core';
@Component({
selector: 'app-testcase-status',
templateUrl: './testcase-status.component.html',
styleUrls: ['./testcase-status.component.scss']
})
export class TestcaseStatusComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
}
import {Problem} from './problem'; import {Problem} from './problem';
export interface User { export interface User {
id: number;
username: string; username: string;
name: string; name: string;
password: string; password: string;
...@@ -10,5 +9,5 @@ export interface User { ...@@ -10,5 +9,5 @@ export interface User {
n_attempts: number; n_attempts: number;
correct_timeline: string; correct_timeline: string;
rating: number; rating: number;
my_questions: Problem; my_questions: Problem[];
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment