feat: refactor logs (#2555)

* feat: refactor logs

* chore: comments

* feat: add system logs

* feat: update shared logs
This commit is contained in:
Alex Inkin
2024-02-06 06:26:00 +04:00
committed by GitHub
parent 4410d7f195
commit 9a0ae549f6
33 changed files with 676 additions and 180 deletions

View File

@@ -25,9 +25,7 @@
</ion-card-content>
</ion-card>
<div class="logs-container">
<logs-window></logs-window>
</div>
<logs-window class="logs" />
</ion-col>
</ion-row>
</ion-grid>

View File

@@ -8,11 +8,15 @@ ion-card-title {
margin: auto auto 40px;
}
.logs-container {
margin-top: 24px;
height: 280px;
.logs {
display: flex;
flex-direction: column;
height: 18rem;
padding: 1rem;
margin: 1.5rem 0.75rem;
text-align: left;
overflow: hidden;
border-radius: 31px;
margin-inline: 10px;
border-radius: 2rem;
// TODO: Theme
background: #181818;
}

View File

@@ -3,12 +3,12 @@ import { CommonModule } from '@angular/common'
import { IonicModule } from '@ionic/angular'
import { TuiLetModule } from '@taiga-ui/cdk'
import { LogsWindowComponent } from './logs-window/logs-window.component'
import { LogsWindowComponent } from './logs-window.component'
import { InitializingComponent } from './initializing.component'
@NgModule({
imports: [CommonModule, IonicModule, TuiLetModule],
declarations: [InitializingComponent, LogsWindowComponent],
imports: [CommonModule, IonicModule, TuiLetModule, LogsWindowComponent],
declarations: [InitializingComponent],
exports: [InitializingComponent],
})
export class InitializingModule {}

View File

@@ -0,0 +1,53 @@
import { AsyncPipe } from '@angular/common'
import { Component, ElementRef, inject } from '@angular/core'
import {
IntersectionObserverModule,
INTERSECTION_ROOT,
} from '@ng-web-apis/intersection-observer'
import { MutationObserverModule } from '@ng-web-apis/mutation-observer'
import { TuiScrollbarModule } from '@taiga-ui/core'
import { NgDompurifyModule } from '@tinkoff/ng-dompurify'
import { SetupLogsService } from '../../services/setup-logs.service'
@Component({
standalone: true,
selector: 'logs-window',
template: `
<tui-scrollbar childList subtree (waMutationObserver)="scrollTo(bottom)">
@for (log of logs$ | async; track log) {
<pre [innerHTML]="log | dompurify"></pre>
}
<section
#bottom
waIntersectionObserver
[style.padding.rem]="1"
(waIntersectionObservee)="onBottom($event)"
></section>
</tui-scrollbar>
`,
imports: [
AsyncPipe,
MutationObserverModule,
IntersectionObserverModule,
NgDompurifyModule,
TuiScrollbarModule,
],
providers: [
{
provide: INTERSECTION_ROOT,
useExisting: ElementRef,
},
],
})
export class LogsWindowComponent {
readonly logs$ = inject(SetupLogsService)
scroll = true
scrollTo(bottom: HTMLElement) {
if (this.scroll) bottom.scrollIntoView({ behavior: 'smooth' })
}
onBottom([{ isIntersecting }]: readonly IntersectionObserverEntry[]) {
this.scroll = isIntersecting
}
}

View File

@@ -1,11 +0,0 @@
<ion-content
[scrollEvents]="true"
(ionScroll)="handleScroll($event)"
(ionScrollEnd)="handleScrollEnd()"
class="ion-padding"
color="light"
>
<div id="container"></div>
</ion-content>
<div id="template"></div>

View File

@@ -1,10 +0,0 @@
// Hide scrollbar for Chrome, Safari and Opera
ion-content::part(scroll)::-webkit-scrollbar {
display: none;
}
// Hide scrollbar for IE, Edge and Firefox
ion-content::part(scroll) {
-ms-overflow-style: none; // IE and Edge
scrollbar-width: none; // Firefox
}

View File

@@ -1,67 +0,0 @@
import { Component, ViewChild } from '@angular/core'
import { IonContent } from '@ionic/angular'
import { map, takeUntil } from 'rxjs'
import { TuiDestroyService } from '@taiga-ui/cdk'
import { SetupLogsService } from '../../../services/setup-logs.service'
import { Log } from '../../../types/api'
import { toLocalIsoString } from '../../../util/to-local-iso-string'
import Convert from 'ansi-to-html'
const convert = new Convert({
bg: 'transparent',
})
@Component({
selector: 'logs-window',
templateUrl: 'logs-window.component.html',
styleUrls: ['logs-window.component.scss'],
providers: [TuiDestroyService],
})
export class LogsWindowComponent {
@ViewChild(IonContent)
private content?: IonContent
autoScroll = true
constructor(
private readonly logs: SetupLogsService,
private readonly destroy$: TuiDestroyService,
) {}
ngOnInit() {
this.logs
.pipe(
map(log => this.convertToAnsi(log)),
takeUntil(this.destroy$),
)
.subscribe(innerHTML => {
const container = document.getElementById('container')
const newLogs = document.getElementById('template')?.cloneNode()
if (!(newLogs instanceof HTMLElement)) return
newLogs.innerHTML = innerHTML
container?.append(newLogs)
if (this.autoScroll) {
setTimeout(() => this.content?.scrollToBottom(250))
}
})
}
handleScroll(e: any) {
if (e.detail.deltaY < 0) this.autoScroll = false
}
async handleScrollEnd() {
const elem = await this.content?.getScrollElement()
if (elem && elem.scrollHeight - elem.scrollTop - elem.clientHeight < 64) {
this.autoScroll = true
}
}
private convertToAnsi(log: Log) {
return `<span style="color: #FFF; font-weight: bold;">${toLocalIsoString(
new Date(log.timestamp),
)}</span>&nbsp;&nbsp;${convert.toHtml(log.message)}<br />`
}
}