2023-07-12 13:21:21 +02:00
< template >
< MainLayout >
< template # dialogs >
< / template >
< template # header >
< TopBar class = "navbar" >
< template # left >
2023-07-12 20:44:56 +02:00
< span class = "title" > { { name } } < / span >
2023-07-12 13:21:21 +02:00
< / template >
< template # right >
< a class = "p-button p-button-primary" style = "margin-right: 5px;" : href = "'/terminal.html?id=' + id" target = "_blank" v-show = "type === 'app'"><span class="p-button-icon p-button-icon-left pi pi-desktop" > < / span > {{ $ t ( ' terminal.title ' ) }} < / a >
2023-07-12 14:22:58 +02:00
< a class = "p-button p-button-primary" style = "margin-right: 5px;" : href = "'/frontend/filemanager.html#/home/app/' + id" target = "_blank" v-show = "type === 'app'"><span class="p-button-icon p-button-icon-left pi pi-folder" > < / span > {{ $ t ( ' filemanager.title ' ) }} < / a >
2023-07-12 13:21:21 +02:00
< Button type = "button" :label = "$t('logs.clear')" icon = "pi pi-eraser" @click ="onClear()" style = "margin-right: 5px" / >
2023-07-12 20:44:56 +02:00
< a class = "p-button p-button-primary" :href = "downloadUrl" target = "_blank" > < span class = "p-button-icon p-button-icon-left pi pi-download" > < / span > { { $t ( 'logs.download' ) } } < / a >
2023-07-12 13:21:21 +02:00
< / template >
< / TopBar >
< / template >
< template # body >
2023-07-12 14:16:48 +02:00
< div v-for = "line in logLines" :key="line.id" class="log-line" >
< span class = "time" > { { line . time } } < / span > < span v-html = "line.html" > < / span >
2023-07-12 13:21:21 +02:00
< / div >
2023-07-12 14:16:48 +02:00
< div ref = "scrollAnchor" class = "bottom-spacer" > < / div >
2023-07-12 13:21:21 +02:00
< / template >
< / MainLayout >
< / template >
< script >
import Button from 'primevue/button' ;
import Dialog from 'primevue/dialog' ;
import InputText from 'primevue/inputtext' ;
import Menu from 'primevue/menu' ;
import ProgressSpinner from 'primevue/progressspinner' ;
2023-07-12 14:39:26 +02:00
import { TopBar , MainLayout } from 'pankow' ;
2023-07-12 13:21:21 +02:00
import { create } from '../models/LogsModel.js' ;
const API _ORIGIN = import . meta . env . VITE _API _ORIGIN ? 'https://' + import . meta . env . VITE _API _ORIGIN : '' ;
export default {
name : 'LogsViewer' ,
components : {
Button ,
Dialog ,
InputText ,
MainLayout ,
Menu ,
ProgressSpinner ,
TopBar
} ,
data ( ) {
return {
accessToken : localStorage . token ,
apiOrigin : API _ORIGIN || '' ,
logsModel : null ,
id : '' ,
name : '' ,
type : '' ,
downloadUrl : '' ,
logLines : [ ]
} ;
} ,
methods : {
onClear ( ) {
this . logLines = [ ] ;
} ,
onDownload ( ) {
this . logsModel . download ( ) ;
}
} ,
async mounted ( ) {
if ( ! localStorage . token ) {
console . error ( 'Set localStorage.token' ) ;
return ;
}
const urlParams = new URLSearchParams ( window . location . search ) ;
const appId = urlParams . get ( 'appId' ) ;
const taskId = urlParams . get ( 'taskId' ) ;
const crashId = urlParams . get ( 'crashId' ) ;
const id = urlParams . get ( 'id' ) ;
if ( appId ) {
this . type = 'app' ;
this . id = appId ;
this . name = 'App ' + appId ;
} else if ( taskId ) {
this . type = 'task' ;
this . id = taskId ;
this . name = 'Task ' + taskId ;
} else if ( crashId ) {
this . type = 'crash' ;
this . id = crashId ;
this . name = 'Crash ' + crashId ;
} else if ( id ) {
if ( id === 'box' ) {
this . type = 'platform' ;
this . id = id ;
this . name = 'Box' ;
} else {
this . type = 'service' ;
this . id = id ;
this . name = 'Service ' + id ;
}
} else {
console . error ( 'no supported log type specified' ) ;
return ;
}
this . logsModel = create ( this . apiOrigin , this . accessToken , this . type , this . id ) ;
if ( this . type === 'app' ) {
try {
const app = await this . logsModel . getApp ( ) ;
this . name = app . fqdn + ' (' + app . manifest . title + ')' ;
} catch ( e ) {
console . error ( ` Failed to get app info for ${ this . id } : ` , e ) ;
}
}
this . downloadUrl = this . logsModel . getDownloadUrl ( ) ;
this . logsModel . stream ( ( id , time , html ) => {
this . logLines . push ( { id , time , html } ) ;
2023-07-12 14:16:48 +02:00
const tmp = document . getElementsByClassName ( 'cloudron-layout-body' ) [ 0 ] ;
if ( ! tmp ) return ;
2023-07-12 13:21:21 +02:00
const autoScroll = tmp . scrollTop > ( tmp . scrollHeight - tmp . clientHeight - 34 ) ;
if ( autoScroll ) setTimeout ( ( ) => this . $refs . scrollAnchor . scrollIntoView ( false ) , 1 ) ;
} , function ( error ) {
console . error ( 'Failed to start log stream:' , error ) ;
} )
}
} ;
< / script >
< style >
body {
background - color : black ;
}
2023-07-12 20:44:56 +02:00
. title {
font - size : 20 px ;
}
2023-07-12 13:21:21 +02:00
. cloudron - layout - body {
cursor : text ;
}
. cloudron - top {
background - color : black ;
color : white ;
margin - bottom : 0 ! important ;
}
. log - line {
color : white ;
font - family : monospace ;
font - size : 14 px ;
line - height : 1.2 ;
white - space : nowrap ;
width : 100 % ;
}
. log - line : hover {
background - color : # 333333 ;
}
. log - line > . time {
color : # 0 ff ;
position : sticky ;
left : 0 ;
margin - right : 10 px ;
background - color : black ;
}
2023-07-12 14:40:35 +02:00
. log - line : hover > . time {
background - color : # 333333 ;
}
2023-07-12 13:21:21 +02:00
. bottom - spacer {
height : 5 px ;
}
2023-07-12 14:37:50 +02:00
a . p - button : hover , a . p - button : focus {
2023-07-12 13:21:21 +02:00
color : white ;
text - decoration : none ;
background : # 0 d89ec ;
border - color : # 0 d89ec ;
}
< / style >