logs for diagnostic ui

This commit is contained in:
Matt Hill
2021-09-16 11:23:30 -06:00
committed by Aiden McClelland
parent f4be73d0d8
commit 8c26e067ff
6 changed files with 187 additions and 3 deletions

View File

@@ -6,6 +6,10 @@ const routes: Routes = [
path: '',
loadChildren: () => import('./pages/home/home.module').then( m => m.HomePageModule)
},
{
path: 'logs',
loadChildren: () => import('./pages/logs/logs.module').then( m => m.LogsPageModule)
},
]
@NgModule({

View File

@@ -1,12 +1,15 @@
<ion-content>
<div style="padding: 48px">
<ng-container *ngIf="!restarted && !forgotten; else refresh">
<h1 class="ion-text-center" style="padding-bottom: 36px; font-size: calc(2vw + 12px);">EmbassyOS - Diagnostic Mode</h1>
<h2 style="padding-bottom: 16px; font-size: calc(1vw + 12px);">EmbassyOS launch error:</h2>
<h1 class="ion-text-center" style="padding-bottom: 36px; font-size: calc(2vw + 14px);">EmbassyOS - Diagnostic Mode</h1>
<h2 style="padding-bottom: 16px; font-size: calc(1vw + 14px); font-weight: bold;">EmbassyOS launch error:</h2>
<div class="code-block">
<code><ion-text color="warning">{{ error.problem }}</ion-text></code>
</div>
<h2 style="padding-bottom: 16px; font-size: calc(1vw + 12px);">Possible solution</h2>
<ion-button routerLink="logs">
View Logs
</ion-button>
<h2 style="padding: 32px 0 16px 0; font-size: calc(1vw + 12px); font-weight: bold;">Possible solution:</h2>
<div class="code-block">
<code><ion-text color="success">{{ error.solution }}</ion-text></code>
</div>

View File

@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { Routes, RouterModule } from '@angular/router'
import { IonicModule } from '@ionic/angular'
import { LogsPage } from './logs.page'
const routes: Routes = [
{
path: '',
component: LogsPage,
},
]
@NgModule({
imports: [
CommonModule,
IonicModule,
RouterModule.forChild(routes),
],
declarations: [LogsPage],
})
export class LogsPageModule { }

View File

@@ -0,0 +1,47 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>Logs</ion-title>
</ion-toolbar>
</ion-header>
<ion-content
[scrollEvents]="true"
(ionScroll)="scrollEvent()"
style="height: 100%;"
id="ion-content"
class="ion-padding"
>
<ion-infinite-scroll id="scroller" *ngIf="!loading && needInfinite" position="top" threshold="0" (ionInfinite)="loadData($event)">
<ion-infinite-scroll-content loadingSpinner="lines"></ion-infinite-scroll-content>
</ion-infinite-scroll>
<div id="container">
<div id="template" style="white-space: pre-line;"></div>
</div>
<div id="button-div" *ngIf="!loading" style="width: 100%; text-align: center;">
<ion-button *ngIf="!loadingMore" (click)="loadMore()" strong color="dark">
Load More
<ion-icon slot="end" name="refresh"></ion-icon>
</ion-button>
<ion-spinner *ngIf="loadingMore" name="lines" color="warning"></ion-spinner>
</div>
<div
*ngIf="!loading"
[ngStyle]="{
'position': 'fixed',
'bottom': '50px',
'right': isOnBottom ? '-52px' : '30px',
'border-radius': '100%',
'transition': 'right 0.4s ease-out'
}"
>
<ion-button style="width: 50px; height: 50px; --padding-start: 0px; --padding-end: 0px; --border-radius: 100%;" color="dark" (click)="scrollToBottom()" strong>
<ion-icon name="chevron-down"></ion-icon>
</ion-button>
</div>
</ion-content>

View File

@@ -0,0 +1,108 @@
import { Component, ViewChild } from '@angular/core'
import { IonContent } from '@ionic/angular'
import { ApiService } from 'src/app/services/api/api.service'
@Component({
selector: 'logs',
templateUrl: './logs.page.html',
styleUrls: ['./logs.page.scss'],
})
export class LogsPage {
@ViewChild(IonContent) private content: IonContent
loading = true
loadingMore = false
logs: string
needInfinite = true
startCursor: string
endCursor: string
limit = 200
scrollToBottomButton = false
isOnBottom = true
constructor (
private readonly api: ApiService,
) { }
ngOnInit () {
this.getLogs()
}
async getLogs () {
try {
// get logs
const logs = await this.fetch()
if (!logs.length) return
const container = document.getElementById('container')
const beforeContainerHeight = container.scrollHeight
const newLogs = document.getElementById('template').cloneNode(true) as HTMLElement
newLogs.innerHTML = logs.map(l => `${l.timestamp} ${l.message}`).join('\n\n') + (logs.length ? '\n\n' : '')
container.prepend(newLogs)
const afterContainerHeight = container.scrollHeight
// scroll down
scrollBy(0, afterContainerHeight - beforeContainerHeight)
this.content.scrollToPoint(0, afterContainerHeight - beforeContainerHeight)
if (logs.length < this.limit) {
this.needInfinite = false
}
} catch (e) { }
}
async fetch (isBefore: boolean = true) {
try {
const cursor = isBefore ? this.startCursor : this.endCursor
const logsRes = await this.api.getLogs({
cursor,
before_flag: !!cursor ? isBefore : undefined,
limit: this.limit,
})
if ((isBefore || this.startCursor) && logsRes['start-cursor']) {
this.startCursor = logsRes['start-cursor']
}
if ((!isBefore || !this.endCursor) && logsRes['end-cursor']) {
this.endCursor = logsRes['end-cursor']
}
this.loading = false
return logsRes.entries
} catch (e) {
console.error(e)
}
}
async loadMore () {
try {
this.loadingMore = true
const logs = await this.fetch(false)
if (!logs.length) return this.loadingMore = false
const container = document.getElementById('container')
const newLogs = document.getElementById('template').cloneNode(true) as HTMLElement
newLogs.innerHTML = logs.map(l => `${l.timestamp} ${l.message}`).join('\n\n') + (logs.length ? '\n\n' : '')
container.append(newLogs)
this.loadingMore = false
this.scrollEvent()
} catch (e) { }
}
scrollEvent () {
const buttonDiv = document.getElementById('button-div')
this.isOnBottom = buttonDiv.getBoundingClientRect().top < window.innerHeight
}
scrollToBottom () {
this.content.scrollToBottom(500)
}
async loadData (e: any): Promise<void> {
await this.getLogs()
e.target.complete()
}
}