From e259315765e91b864b0b62026ead53cc12913c7b Mon Sep 17 00:00:00 2001 From: jmbardallo Date: Wed, 25 Mar 2026 15:04:07 +0100 Subject: [PATCH] Se ha mejorado el editor de menus para poder editar directamente la plantilla twig en lugar del html renderizado. --- CHANGELOG.md | 4 ++ .../create-menu/create-menu.component.ts | 42 +++++++++++++------ .../src/app/components/menus/data.service.ts | 20 +++++++++ 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ac4d2b..91b9aee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## [1.2.4] - 2026-03-20 +### Added +- Se ha mejorado el editor de menus para poder editar directamente la plantilla twig en lugar del html renderizado. + ## [1.2.3] - 2026-03-17 ### Added - Se ha creado una nueva opción para gestionar assets en la pantalla de menus. diff --git a/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.ts b/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.ts index 94bccd7..bf04d47 100644 --- a/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.ts +++ b/ogWebconsole/src/app/components/menus/create-menu/create-menu.component.ts @@ -88,15 +88,15 @@ export class CreateMenuComponent implements OnInit { } this.isEditingHtml = true; } else if (this.menuForm.get('publicUrl')?.value) { - // Fetch the actual HTML from the public URL if it exists and no file was manually uploaded yet - const url = `${this.baseUrl}/menu/${this.menuForm.get('publicUrl')?.value}`; - this.http.get(url, { responseType: 'text' }).subscribe({ + // Fetch the actual raw HTML/Twig template if it exists and no file was manually uploaded yet + const publicUrl = this.menuForm.get('publicUrl')?.value; + this.dataService.getRawMenuTemplate(publicUrl).subscribe({ next: (htmlStr) => { this.htmlEditorContent = htmlStr; this.isEditingHtml = true; }, error: (err) => { - this.toastService.error('No se pudo descargar el HTML actual del menú para editarlo.'); + this.toastService.error('No se pudo descargar el HTML/Twig original del menú para editarlo.'); console.error(err); } }); @@ -105,22 +105,38 @@ export class CreateMenuComponent implements OnInit { applyHtmlChanges(): void { if (this.htmlEditorContent) { - // Encode the typed text back into Base64 enforcing UTF-8 compatibility + // Encode the drafted Twig code back into Base64 enforcing UTF-8 compatibility try { - // Modern approach to encode UTF-8 string to Base64 const bytes = new TextEncoder().encode(this.htmlEditorContent); const binaryStr = Array.from(bytes).map(byte => String.fromCharCode(byte)).join(''); - this.fileContent = window.btoa(binaryStr); + const base64Content = window.btoa(binaryStr); + + // This holds the RAW twig that will be sent via PUT/POST on save + this.fileContent = base64Content; + + // Ask the backend to compile a preview using this encoded Twig + this.dataService.previewMenuTemplate(base64Content).subscribe({ + next: (renderedHtml) => { + // Now encode the definitively rendered HTML to Base64 to populate the iframe preview + const renderedBytes = new TextEncoder().encode(renderedHtml); + const renderedBinaryStr = Array.from(renderedBytes).map(byte => String.fromCharCode(byte)).join(''); + const renderedBase64 = window.btoa(renderedBinaryStr); + + this.isEditingHtml = false; + const dataUrl = `data:text/html;base64,${renderedBase64}`; + this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(dataUrl); + this.toastService.success('Vista previa generada. Pulsa Guardar para aplicar la plantilla remota permanentemente.'); + }, + error: (err) => { + console.error('Failed to preview generated HTML', err); + const msg = err.error?.message || 'Error compilando la plantilla Twig.'; + this.toastService.error(msg); + } + }); - // Switch to preview mode and update the iframe source to use the fresh Base64 - this.isEditingHtml = false; - const dataUrl = `data:text/html;base64,${this.fileContent}`; - this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(dataUrl); - this.toastService.success('Cambios aplicados temporalmente. Pulsa Guardar para subirlos al servidor.'); } catch (e) { console.error('Failed to encode updated HTML to Base64', e); this.toastService.error('Hubo un problema procesando los caracteres especiales del HTML.'); - // En caso de error, nos mantenemos en la vista de edición para que el usuario pueda corregirlo } } } diff --git a/ogWebconsole/src/app/components/menus/data.service.ts b/ogWebconsole/src/app/components/menus/data.service.ts index 6086d5c..b61dfe0 100644 --- a/ogWebconsole/src/app/components/menus/data.service.ts +++ b/ogWebconsole/src/app/components/menus/data.service.ts @@ -16,6 +16,26 @@ export class DataService { this.apiUrl = `${this.baseUrl}/menus?page=1&itemsPerPage=1000`; } + getRawMenuTemplate(publicUrl: string): Observable { + const url = `${this.baseUrl}/menu-raw/${publicUrl}`; + return this.http.get(url, { responseType: 'text' }).pipe( + catchError(error => { + console.error('Error fetching raw menu template', error); + return throwError(() => error); + }) + ); + } + + previewMenuTemplate(base64Template: string): Observable { + const url = `${this.baseUrl}/menu-preview`; + return this.http.post(url, { templateBase64: base64Template }, { responseType: 'text' }).pipe( + catchError(error => { + console.error('Error previewing menu template', error); + return throwError(() => error); + }) + ); + } + getMenus(filters: { [key: string]: string }): Observable<{ totalItems: any; data: any }> { const params = new HttpParams({ fromObject: filters }); -- 2.40.1