From 8330d4ded1b8faf0c55c1dd2bf9b2a565aff89c5 Mon Sep 17 00:00:00 2001 From: Pushkar Mishra Date: Sat, 6 Sep 2025 21:45:18 +0530 Subject: [PATCH 1/3] feat: integrate CompilerService for Rust code compilation and testing - Added CompilerService to the EditorComponent for handling code compilation and testing. - Updated onCompile and onTest methods to utilize the CompilerService for API calls, replacing previous timeout-based simulation. - Included HttpClient in app configuration for improved HTTP handling. Signed-off-by: Pushkar Mishra --- apps/frontend/src/app/app.config.ts | 4 +- .../app/components/editor/editor.component.ts | 38 ++++++--- .../src/app/services/compiler.spec.ts | 16 ++++ apps/frontend/src/app/services/compiler.ts | 85 +++++++++++++++++++ 4 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 apps/frontend/src/app/services/compiler.spec.ts create mode 100644 apps/frontend/src/app/services/compiler.ts diff --git a/apps/frontend/src/app/app.config.ts b/apps/frontend/src/app/app.config.ts index 90081d9..ea27f81 100644 --- a/apps/frontend/src/app/app.config.ts +++ b/apps/frontend/src/app/app.config.ts @@ -1,5 +1,6 @@ import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection, NgZone } from '@angular/core'; import { provideRouter } from '@angular/router'; +import { provideHttpClient, withFetch } from '@angular/common/http'; import { MONACO_PATH, MonacoEditorLoaderService } from '@materia-ui/ngx-monaco-editor'; import { routes } from './app.routes'; @@ -9,7 +10,8 @@ export const appConfig: ApplicationConfig = { providers: [ provideBrowserGlobalErrorListeners(), provideZonelessChangeDetection(), - provideRouter(routes), + provideRouter(routes), + provideHttpClient(withFetch()), provideClientHydration(withEventReplay()), { provide: MONACO_PATH, diff --git a/apps/frontend/src/app/components/editor/editor.component.ts b/apps/frontend/src/app/components/editor/editor.component.ts index 71c17d0..59069f9 100644 --- a/apps/frontend/src/app/components/editor/editor.component.ts +++ b/apps/frontend/src/app/components/editor/editor.component.ts @@ -3,6 +3,7 @@ import { CommonModule, isPlatformBrowser } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'; import { PLATFORM_ID, inject } from '@angular/core'; +import { CompilerService } from '../../services/compiler'; const DEFAULT_RUST_CODE = `// Welcome to Soroban Smart Contract Editor @@ -34,6 +35,8 @@ export class EditorComponent implements OnDestroy { isLoading = false; isBrowser = isPlatformBrowser(inject(PLATFORM_ID)); + private compilerService = inject(CompilerService); + editorOptions = { theme: 'vs-dark', language: 'rust', @@ -50,6 +53,7 @@ export class EditorComponent implements OnDestroy { this.timeoutIds.clear(); } + onCompile(): void { if (this.isLoading || !this.code.trim()) { return; @@ -58,13 +62,16 @@ export class EditorComponent implements OnDestroy { this.isLoading = true; console.log('Compiling Rust smart contract code:', this.code); - // TODO: Implement API call to backend compiler - const timeoutId = setTimeout(() => { - this.isLoading = false; - this.timeoutIds.delete(timeoutId); - console.log('Compilation complete'); - }, 2000) as unknown as number; - this.timeoutIds.add(timeoutId); + this.compilerService.compile(this.code).subscribe({ + next: (response) => { + this.isLoading = false; + console.log('Compilation response:', response); + }, + error: (error) => { + this.isLoading = false; + console.error('Compilation error:', error); + } + }); } onTest(): void { @@ -75,12 +82,15 @@ export class EditorComponent implements OnDestroy { this.isLoading = true; console.log('Testing Rust smart contract code:', this.code); - // TODO: Implement API call to backend test runner - const timeoutId = setTimeout(() => { - this.isLoading = false; - this.timeoutIds.delete(timeoutId); - console.log('Testing complete'); - }, 2000) as unknown as number; - this.timeoutIds.add(timeoutId); + this.compilerService.test(this.code).subscribe({ + next: (response) => { + this.isLoading = false; + console.log('Test response:', response); + }, + error: (error) => { + this.isLoading = false; + console.error('Test error:', error); + } + }); } } diff --git a/apps/frontend/src/app/services/compiler.spec.ts b/apps/frontend/src/app/services/compiler.spec.ts new file mode 100644 index 0000000..79f6569 --- /dev/null +++ b/apps/frontend/src/app/services/compiler.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { Compiler } from './compiler'; + +describe('Compiler', () => { + let service: Compiler; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(Compiler); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/apps/frontend/src/app/services/compiler.ts b/apps/frontend/src/app/services/compiler.ts new file mode 100644 index 0000000..f818033 --- /dev/null +++ b/apps/frontend/src/app/services/compiler.ts @@ -0,0 +1,85 @@ +import { Injectable, inject } from '@angular/core'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +// Define interfaces for type safety +export interface CompileRequest { + code: string; +} + +export interface CompileResponse { + output: string; + success?: boolean; + error?: string; +} + +export interface TestResponse { + output: string; + success?: boolean; + error?: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class CompilerService { + private readonly API_BASE_URL = 'http://localhost:3000/api'; + private http = inject(HttpClient); + + /** + * Compile Rust smart contract code + */ + compile(code: string): Observable { + const request: CompileRequest = { code }; + + return this.http.post(`${this.API_BASE_URL}/compile`, request) + .pipe( + map(response => ({ + ...response, + success: true + })), + catchError(this.handleError) + ); + } + + /** + * Test Rust smart contract code + */ + test(code: string): Observable { + const request: CompileRequest = { code }; + + return this.http.post(`${this.API_BASE_URL}/test`, request) + .pipe( + map(response => ({ + ...response, + success: true + })), + catchError(this.handleError) + ); + } + + /** + * Handle HTTP errors + */ + private handleError(error: HttpErrorResponse): Observable { + let errorMessage = 'An unknown error occurred'; + + if (error.error instanceof ErrorEvent) { + // Client-side error + errorMessage = `Error: ${error.error.message}`; + } else { + // Server-side error + errorMessage = error.error?.message || + error.error?.output || + `Server Error: ${error.status} - ${error.statusText}`; + } + + console.error('CompilerService Error:', errorMessage); + return throwError(() => ({ + output: errorMessage, + success: false, + error: errorMessage + })); + } +} From dc667b78fffcf4244be7698417356b829c5cf358 Mon Sep 17 00:00:00 2001 From: Pushkar Mishra Date: Mon, 8 Sep 2025 18:05:51 +0530 Subject: [PATCH 2/3] fix Signed-off-by: Pushkar Mishra --- .../components/editor/editor.component.css | 34 ++++++++- .../components/editor/editor.component.html | 48 ++++++++++++ .../app/components/editor/editor.component.ts | 75 ++++++++++++++++++- 3 files changed, 153 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/app/components/editor/editor.component.css b/apps/frontend/src/app/components/editor/editor.component.css index a381834..efd7a44 100644 --- a/apps/frontend/src/app/components/editor/editor.component.css +++ b/apps/frontend/src/app/components/editor/editor.component.css @@ -1,4 +1,13 @@ -/* Monaco Editor Deep Styling */ +/* Editor Container Styles */ +.editor-container { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; +} + +/* Monaco Editor Custom Styles */ +:host ::ng-deep .monaco-editor { + padding-top: 0px; +} + :host ::ng-deep .monaco-editor .margin { background-color: #1f2937; } @@ -64,6 +73,29 @@ @apply focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-gray-900 rounded-lg; } +/* Editor Footer */ +.editor-footer { + backdrop-filter: blur(10px); + background-color: rgba(31, 41, 55, 0.95); +} + +/* Output panel animations */ +.animate-slide-down { + animation: slide-in-from-top 0.3s ease-out; +} + +/* Custom animations for smooth transitions */ +@keyframes slide-in-from-top { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + /* Code syntax highlighting enhancements */ .code-highlight { @apply font-mono text-sm leading-relaxed; diff --git a/apps/frontend/src/app/components/editor/editor.component.html b/apps/frontend/src/app/components/editor/editor.component.html index 5f19e77..72bb503 100644 --- a/apps/frontend/src/app/components/editor/editor.component.html +++ b/apps/frontend/src/app/components/editor/editor.component.html @@ -73,6 +73,54 @@

Soroban Smar + +
+
+
+
+ +
+ + + + + + + + + +
+ + +
+

+ {{ errorMessage || outputMessage }} +

+
+
+ + + +
+
+
+