mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-02 05:23:14 +00:00
ui: adds agent logs page in server show
This commit is contained in:
committed by
Aiden McClelland
parent
327c79350e
commit
a9735fd777
@@ -0,0 +1,28 @@
|
|||||||
|
import { NgModule } from '@angular/core'
|
||||||
|
import { CommonModule } from '@angular/common'
|
||||||
|
import { Routes, RouterModule } from '@angular/router'
|
||||||
|
|
||||||
|
import { IonicModule } from '@ionic/angular'
|
||||||
|
|
||||||
|
import { ServerLogsPage } from './server-logs.page'
|
||||||
|
import { PwaBackComponentModule } from 'src/app/components/pwa-back-button/pwa-back.component.module'
|
||||||
|
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: ServerLogsPage,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
IonicModule,
|
||||||
|
RouterModule.forChild(routes),
|
||||||
|
PwaBackComponentModule,
|
||||||
|
BadgeMenuComponentModule,
|
||||||
|
],
|
||||||
|
declarations: [ServerLogsPage],
|
||||||
|
})
|
||||||
|
export class ServerLogsPageModule { }
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<pwa-back-button></pwa-back-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>Logs</ion-title>
|
||||||
|
<ion-buttons slot="end" class="ion-padding-end">
|
||||||
|
<ion-button (click)="getLogs()" color="primary">
|
||||||
|
<ion-icon name="refresh-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<badge-menu-button></badge-menu-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content class="ion-padding" color="light">
|
||||||
|
<ion-item *ngIf="error" style="margin-bottom: 16px;">
|
||||||
|
<ion-text class="ion-text-wrap" color="danger">{{ error }}</ion-text>
|
||||||
|
</ion-item>
|
||||||
|
<ion-spinner *ngIf="$loading$ | async" class="center" name="lines" color="warning"></ion-spinner>
|
||||||
|
<p style="white-space: pre-line;">{{ logs }}</p>
|
||||||
|
</ion-content>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { Component, ViewChild } from '@angular/core'
|
||||||
|
import { ActivatedRoute } from '@angular/router'
|
||||||
|
import { ApiService } from 'src/app/services/api/api.service'
|
||||||
|
import { IonContent } from '@ionic/angular'
|
||||||
|
import { pauseFor } from 'src/app/util/misc.util'
|
||||||
|
import { markAsLoadingDuringP } from 'src/app/services/loader.service'
|
||||||
|
import { BehaviorSubject } from 'rxjs'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'server-logs',
|
||||||
|
templateUrl: './server-logs.page.html',
|
||||||
|
styleUrls: ['./server-logs.page.scss'],
|
||||||
|
})
|
||||||
|
export class ServerLogsPage {
|
||||||
|
@ViewChild(IonContent, { static: false }) private content: IonContent
|
||||||
|
$loading$ = new BehaviorSubject(true)
|
||||||
|
error = ''
|
||||||
|
logs: string
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private readonly apiService: ApiService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async ngOnInit () {
|
||||||
|
markAsLoadingDuringP(this.$loading$, Promise.all([
|
||||||
|
this.getLogs(),
|
||||||
|
pauseFor(600),
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLogs () {
|
||||||
|
this.logs = ''
|
||||||
|
this.$loading$.next(true)
|
||||||
|
try {
|
||||||
|
this.logs = await this.apiService.getServerLogs()
|
||||||
|
this.error = ''
|
||||||
|
setTimeout(async () => await this.content.scrollToBottom(100), 200)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
this.error = e.message
|
||||||
|
} finally {
|
||||||
|
this.$loading$.next(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,11 @@ const routes: Routes = [
|
|||||||
canActivate: [AuthGuard],
|
canActivate: [AuthGuard],
|
||||||
loadChildren: () => import('./server-metrics/server-metrics.module').then(m => m.ServerMetricsPageModule),
|
loadChildren: () => import('./server-metrics/server-metrics.module').then(m => m.ServerMetricsPageModule),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'logs',
|
||||||
|
canActivate: [AuthGuard],
|
||||||
|
loadChildren: () => import('./server-logs/server-logs.module').then(m => m.ServerLogsPageModule),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'config',
|
path: 'config',
|
||||||
canActivate: [AuthGuard],
|
canActivate: [AuthGuard],
|
||||||
|
|||||||
@@ -47,6 +47,11 @@
|
|||||||
<ion-label><ion-text color="primary">Monitor</ion-text></ion-label>
|
<ion-label><ion-text color="primary">Monitor</ion-text></ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item [routerLink]="['logs']">
|
||||||
|
<ion-icon slot="start" name="newspaper-outline" color="primary"></ion-icon>
|
||||||
|
<ion-label><ion-text color="primary">Logs</ion-text></ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
<ion-item lines="none" [routerLink]="['config']">
|
<ion-item lines="none" [routerLink]="['config']">
|
||||||
<ion-icon slot="start" name="cog-outline" color="primary"></ion-icon>
|
<ion-icon slot="start" name="cog-outline" color="primary"></ion-icon>
|
||||||
<ion-label><ion-text color="primary">Config</ion-text></ion-label>
|
<ion-label><ion-text color="primary">Config</ion-text></ion-label>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export abstract class ApiService {
|
|||||||
abstract getExternalDisks (): Promise<DiskInfo[]>
|
abstract getExternalDisks (): Promise<DiskInfo[]>
|
||||||
abstract getAppConfig (appId: string): Promise<{ spec: ConfigSpec, config: object, rules: Rules[]}>
|
abstract getAppConfig (appId: string): Promise<{ spec: ConfigSpec, config: object, rules: Rules[]}>
|
||||||
abstract getAppLogs (appId: string, params?: ReqRes.GetAppLogsReq): Promise<string[]>
|
abstract getAppLogs (appId: string, params?: ReqRes.GetAppLogsReq): Promise<string[]>
|
||||||
|
abstract getServerLogs (): Promise<string>
|
||||||
abstract installApp (appId: string, version: string, dryRun?: boolean): Promise<AppInstalledFull & { breakages: DependentBreakage[] } >
|
abstract installApp (appId: string, version: string, dryRun?: boolean): Promise<AppInstalledFull & { breakages: DependentBreakage[] } >
|
||||||
abstract uninstallApp (appId: string, dryRun?: boolean): Promise<{ breakages: DependentBreakage[] }>
|
abstract uninstallApp (appId: string, dryRun?: boolean): Promise<{ breakages: DependentBreakage[] }>
|
||||||
abstract startApp (appId: string): Promise<Unit>
|
abstract startApp (appId: string): Promise<Unit>
|
||||||
@@ -76,7 +77,9 @@ export module ReqRes {
|
|||||||
export type GetAppInstalledRes = ApiAppInstalledFull
|
export type GetAppInstalledRes = ApiAppInstalledFull
|
||||||
export type GetAppConfigRes = ApiAppConfig
|
export type GetAppConfigRes = ApiAppConfig
|
||||||
export type GetAppLogsReq = { after?: string, before?: string, page?: string, perPage?: string }
|
export type GetAppLogsReq = { after?: string, before?: string, page?: string, perPage?: string }
|
||||||
|
export type GetServerLogsReq = { }
|
||||||
export type GetAppLogsRes = string[]
|
export type GetAppLogsRes = string[]
|
||||||
|
export type GetServerLogsRes = string
|
||||||
export type GetAppMetricsRes = AppMetricsVersioned<number>
|
export type GetAppMetricsRes = AppMetricsVersioned<number>
|
||||||
export type GetAppsInstalledRes = AppInstalledPreview[]
|
export type GetAppsInstalledRes = AppInstalledPreview[]
|
||||||
export type PostInstallAppReq = { version: string }
|
export type PostInstallAppReq = { version: string }
|
||||||
|
|||||||
@@ -123,6 +123,10 @@ export class LiveApiService extends ApiService {
|
|||||||
return this.authRequest<ReqRes.GetAppLogsRes>( { method: Method.GET, url: `/apps/${appId}/logs`, params: params as any })
|
return this.authRequest<ReqRes.GetAppLogsRes>( { method: Method.GET, url: `/apps/${appId}/logs`, params: params as any })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getServerLogs (): Promise<string> {
|
||||||
|
return this.authRequest<ReqRes.GetServerLogsRes>( { method: Method.GET, url: `/logs` })
|
||||||
|
}
|
||||||
|
|
||||||
async getAppMetrics (appId: string): Promise<AppMetrics> {
|
async getAppMetrics (appId: string): Promise<AppMetrics> {
|
||||||
return this.authRequest<ReqRes.GetAppMetricsRes | string>( { method: Method.GET, url: `/apps/${appId}/metrics` })
|
return this.authRequest<ReqRes.GetAppMetricsRes | string>( { method: Method.GET, url: `/apps/${appId}/metrics` })
|
||||||
.then(parseMetricsPermissive)
|
.then(parseMetricsPermissive)
|
||||||
|
|||||||
@@ -113,6 +113,10 @@ export class MockApiService extends ApiService {
|
|||||||
return mockGetAppLogs()
|
return mockGetAppLogs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getServerLogs (): Promise<string> {
|
||||||
|
return mockGetServerLogs()
|
||||||
|
}
|
||||||
|
|
||||||
async installApp (appId: string, version: string, dryRun: boolean): Promise<AppInstalledFull & { breakages: DependentBreakage[] }> {
|
async installApp (appId: string, version: string, dryRun: boolean): Promise<AppInstalledFull & { breakages: DependentBreakage[] }> {
|
||||||
return mockInstallApp(appId)
|
return mockInstallApp(appId)
|
||||||
}
|
}
|
||||||
@@ -271,6 +275,11 @@ async function mockGetAppLogs (): Promise<ReqRes.GetAppLogsRes> {
|
|||||||
return mockApiAppLogs
|
return mockApiAppLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function mockGetServerLogs (): Promise<ReqRes.GetServerLogsRes> {
|
||||||
|
await pauseFor(1000)
|
||||||
|
return mockApiServerLogs.join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
async function mockGetAppMetrics (): Promise<ReqRes.GetAppMetricsRes> {
|
async function mockGetAppMetrics (): Promise<ReqRes.GetAppMetricsRes> {
|
||||||
await pauseFor(1000)
|
await pauseFor(1000)
|
||||||
return mockApiAppMetricsV1
|
return mockApiAppMetricsV1
|
||||||
@@ -610,6 +619,91 @@ const mockApiAppLogs: string[] = [
|
|||||||
'****** FINISH *****',
|
'****** FINISH *****',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const mockApiServerLogs: string[] = [
|
||||||
|
'****** START *****',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:20:30.872Z - Hash: 2b2e5abb3cba2164aea0',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1244ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:21:01.685Z - Hash: bb3f5d0e11f2cd2dd57b',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1185ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:23:13.812Z - Hash: 9342e11e6b8e16ad2f70',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:20:30.872Z - Hash: 2b2e5abb3cba2164aea0',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1244ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:21:01.685Z - Hash: bb3f5d0e11f2cd2dd57b',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1185ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:23:13.812Z - Hash: 9342e11e6b8e16ad2f70',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:20:30.872Z - Hash: 2b2e5abb3cba2164aea0',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1244ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:21:01.685Z - Hash: bb3f5d0e11f2cd2dd57b',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1185ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:23:13.812Z - Hash: 9342e11e6b8e16ad2f70',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:20:30.872Z - Hash: 2b2e5abb3cba2164aea0',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1244ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:21:01.685Z - Hash: bb3f5d0e11f2cd2dd57b',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1185ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:23:13.812Z - Hash: 9342e11e6b8e16ad2f70',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:20:30.872Z - Hash: 2b2e5abb3cba2164aea0',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1244ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:21:01.685Z - Hash: bb3f5d0e11f2cd2dd57b',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'[ng] chunk {app-logs-app-logs-module} app-logs-app-logs-module.js, app-logs-app-logs-module.js.map (app-logs-app-logs-module) 7.86 kB [rendered]',
|
||||||
|
'[ng] Time: 1185ms',
|
||||||
|
'[ng] ℹ 「wdm」: Compiled successfully.',
|
||||||
|
'[ng] ℹ 「wdm」: Compiling...',
|
||||||
|
'[ng] Date: 2019-12-26T14:23:13.812Z - Hash: 9342e11e6b8e16ad2f70',
|
||||||
|
'[ng] 114 unchanged chunks',
|
||||||
|
'****** FINISH *****',
|
||||||
|
]
|
||||||
|
|
||||||
const mockApiAppMetricsV1: AppMetricsVersioned<2> = {
|
const mockApiAppMetricsV1: AppMetricsVersioned<2> = {
|
||||||
version: 2,
|
version: 2,
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
Reference in New Issue
Block a user