json viewer
This commit is contained in:
101
client/src/app/json-file-viewer.component.ts
Normal file
101
client/src/app/json-file-viewer.component.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core';
|
||||
|
||||
import type { ChatEntry } from './models';
|
||||
|
||||
type JsonViewTree = object;
|
||||
|
||||
type JsonViewApi = {
|
||||
renderJSON(value: unknown, container: HTMLElement): JsonViewTree;
|
||||
expand?(tree: JsonViewTree): void;
|
||||
destroy?(tree: JsonViewTree): void;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
jsonview?: JsonViewApi;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-json-file-viewer',
|
||||
imports: [CommonModule],
|
||||
template: `
|
||||
<div class="json-viewer-shell">
|
||||
<div #host class="json-viewer-host"></div>
|
||||
@if (errorMessage) {
|
||||
<p class="json-viewer-error mb-0">{{ errorMessage }}</p>
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
styleUrl: './json-file-viewer.component.scss',
|
||||
})
|
||||
export class JsonFileViewerComponent implements AfterViewInit, OnChanges, OnDestroy {
|
||||
@Input({ required: true }) entry!: ChatEntry;
|
||||
@ViewChild('host') private readonly host?: ElementRef<HTMLDivElement>;
|
||||
|
||||
errorMessage: string | null = null;
|
||||
private renderedTree: JsonViewTree | null = null;
|
||||
private renderVersion = 0;
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
void this.renderJsonTree();
|
||||
}
|
||||
|
||||
ngOnChanges(): void {
|
||||
void this.renderJsonTree();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroyRenderedTree();
|
||||
}
|
||||
|
||||
private async renderJsonTree(): Promise<void> {
|
||||
const host = this.host?.nativeElement;
|
||||
|
||||
if (!host || !this.entry.downloadUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const renderVersion = ++this.renderVersion;
|
||||
const jsonview = window.jsonview;
|
||||
|
||||
this.destroyRenderedTree();
|
||||
host.replaceChildren();
|
||||
this.errorMessage = null;
|
||||
|
||||
if (!jsonview) {
|
||||
this.errorMessage = 'JSON viewer unavailable.';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(this.entry.downloadUrl);
|
||||
const content = await response.text();
|
||||
const parsed = JSON.parse(content);
|
||||
|
||||
if (renderVersion !== this.renderVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tree = jsonview.renderJSON(parsed, host);
|
||||
jsonview.expand?.(tree);
|
||||
this.renderedTree = tree;
|
||||
} catch {
|
||||
if (renderVersion !== this.renderVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.errorMessage = 'Could not render JSON preview.';
|
||||
}
|
||||
}
|
||||
|
||||
private destroyRenderedTree(): void {
|
||||
if (!this.renderedTree) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.jsonview?.destroy?.(this.renderedTree);
|
||||
this.renderedTree = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user