From 39a1a80ebbc721c58108131ba6369c17ab6c11fa Mon Sep 17 00:00:00 2001 From: vato007 Date: Sun, 14 Jul 2024 14:54:26 +0930 Subject: [PATCH] Add save as, support for downloading in the browser and workaround for tauri bug --- src/app/editor/editor.component.html | 4 +- src/app/editor/editor.component.ts | 69 +++++++++++-------- .../proto-definition-selector.component.ts | 27 +++++++- src/styles.scss | 1 - 4 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index 0d43eb9..a8772d5 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -1,6 +1,6 @@

{{ selectedMessage().name }}

-
@@ -22,3 +22,5 @@
} + + diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts index 9637c96..95a94c5 100644 --- a/src/app/editor/editor.component.ts +++ b/src/app/editor/editor.component.ts @@ -3,31 +3,28 @@ import { Component, ElementRef, SecurityContext, + computed, effect, input, signal, viewChild, } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; import { MatSnackBar } from '@angular/material/snack-bar'; import { DomSanitizer } from '@angular/platform-browser'; import { readTextFile, writeTextFile } from '@tauri-apps/api/fs'; import hljs from 'highlight.js/lib/core'; import { ProtoMessage } from '../model/proto-message.model'; import { ProtoFieldComponent } from './proto-field/proto-field.component'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { save } from '@tauri-apps/api/dialog'; + +declare const __TAURI__: any; @Component({ selector: 'app-editor', standalone: true, - imports: [ - CommonModule, - ProtoFieldComponent, - MatButtonModule, - MatIconModule, - MatTooltipModule, - ], + imports: [CommonModule, ProtoFieldComponent, MatButtonModule, MatIconModule], templateUrl: './editor.component.html', styleUrl: './editor.component.scss', }) @@ -35,10 +32,22 @@ export class EditorComponent { selectedFile = input(); selectedMessage = input.required(); indentSize = input(2); - showRaw = input(true); protected values = signal(undefined); + protected downloadName = computed( + () => this.selectedFile() ?? `${this.selectedMessage.name}.json` + ); + private serialisedValues = computed(() => + JSON.stringify(this.values(), undefined, this.indentSize()) + ); + protected saveHref = computed(() => { + const blob = new Blob([this.serialisedValues()], { + type: 'application/json', + }); + return URL.createObjectURL(blob); + }); + protected downloader = viewChild>('downloader'); private code = viewChild>('code'); @@ -49,11 +58,7 @@ export class EditorComponent { if (!this.values()) { return; } - const json = JSON.stringify( - this.values(), - undefined, - this.indentSize() - ); + const json = this.serialisedValues(); const highlighted = hljs.highlightAuto(json, ['json']); const sanitized = sanitizer.sanitize( SecurityContext.HTML, @@ -78,7 +83,6 @@ export class EditorComponent { effect(async () => { const selectedFile = this.selectedFile(); - console.log('selected file' + selectedFile); if (selectedFile) { const fileContents = await readTextFile(selectedFile); try { @@ -106,9 +110,7 @@ export class EditorComponent { } protected async copyToClipboard() { - await navigator.clipboard.writeText( - JSON.stringify(this.values(), undefined, this.indentSize()) - ); + await navigator.clipboard.writeText(this.serialisedValues()); this.snackBar.open('Successully copied to clipboard', 'Close', { duration: 2000, }); @@ -116,16 +118,25 @@ export class EditorComponent { protected async save() { const selectedFile = this.selectedFile(); - if (!selectedFile) { - return; - } - try { - await writeTextFile( - selectedFile, - JSON.stringify(this.values(), undefined, this.indentSize()) - ); - } catch (err) { - console.error('Failed to write to file ${this.selectedFile()}', err); + if (__TAURI__) { + const serialised = this.serialisedValues(); + // TODO: Tauri is bugged on mac atm, remove this when resolved: https://github.com/tauri-apps/tauri/issues/4633 + if (selectedFile) { + try { + await writeTextFile(selectedFile, serialised); + } catch (err) { + console.error('Failed to write to file ${this.selectedFile()}', err); + } + } else { + const filePath = await save({ + defaultPath: `${this.selectedMessage().name}.json`, + }); + if (filePath) { + await writeTextFile(filePath, serialised); + } + } + } else { + this.downloader()?.nativeElement.click(); } } } diff --git a/src/app/proto-definition-selector/proto-definition-selector.component.ts b/src/app/proto-definition-selector/proto-definition-selector.component.ts index ff2f3ca..b4a2f53 100644 --- a/src/app/proto-definition-selector/proto-definition-selector.component.ts +++ b/src/app/proto-definition-selector/proto-definition-selector.component.ts @@ -16,6 +16,10 @@ import { ProtoMessage } from '../model/proto-message.model'; import { ProtoDefinitionService } from './proto-definition.service'; import { MatTreeModule } from '@angular/material/tree'; import { MatSnackBar } from '@angular/material/snack-bar'; +import { writeTextFile } from '@tauri-apps/api/fs'; +import { save } from '@tauri-apps/api/dialog'; + +declare const __TAURI__: any; @Component({ selector: 'app-proto-definition-selector', @@ -27,7 +31,9 @@ import { MatSnackBar } from '@angular/material/snack-bar'; Select definitions @if(currentFiles().length > 0) { - + }