diff --git a/diagnostic-ui/src/app/app-routing.module.ts b/diagnostic-ui/src/app/app-routing.module.ts index 4c88ac1dc..fffdfeece 100644 --- a/diagnostic-ui/src/app/app-routing.module.ts +++ b/diagnostic-ui/src/app/app-routing.module.ts @@ -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({ diff --git a/diagnostic-ui/src/app/pages/home/home.page.html b/diagnostic-ui/src/app/pages/home/home.page.html index 7e6bad01a..8980af238 100644 --- a/diagnostic-ui/src/app/pages/home/home.page.html +++ b/diagnostic-ui/src/app/pages/home/home.page.html @@ -1,12 +1,15 @@
-

EmbassyOS - Diagnostic Mode

-

EmbassyOS launch error:

+

EmbassyOS - Diagnostic Mode

+

EmbassyOS launch error:

{{ error.problem }}
-

Possible solution

+ + View Logs + +

Possible solution:

{{ error.solution }}
diff --git a/diagnostic-ui/src/app/pages/logs/logs.module.ts b/diagnostic-ui/src/app/pages/logs/logs.module.ts new file mode 100644 index 000000000..da4d046b4 --- /dev/null +++ b/diagnostic-ui/src/app/pages/logs/logs.module.ts @@ -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 { } diff --git a/diagnostic-ui/src/app/pages/logs/logs.page.html b/diagnostic-ui/src/app/pages/logs/logs.page.html new file mode 100644 index 000000000..151ca61ee --- /dev/null +++ b/diagnostic-ui/src/app/pages/logs/logs.page.html @@ -0,0 +1,47 @@ + + + + + + Logs + + + + + + + + +
+
+
+
+ + Load More + + + +
+ +
+ + + +
+ +
diff --git a/diagnostic-ui/src/app/pages/logs/logs.page.scss b/diagnostic-ui/src/app/pages/logs/logs.page.scss new file mode 100644 index 000000000..e69de29bb diff --git a/diagnostic-ui/src/app/pages/logs/logs.page.ts b/diagnostic-ui/src/app/pages/logs/logs.page.ts new file mode 100644 index 000000000..b96fe8c3a --- /dev/null +++ b/diagnostic-ui/src/app/pages/logs/logs.page.ts @@ -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 { + await this.getLogs() + e.target.complete() + } +} +