Log Viewer: Add text mode option (#3177)
- Add an option to display the log in "Text mode" vs "Table mode". - In Text Mode, the "Copy" button will copy the log as plain text. In Table Mode, the "Copy" button does what it used to do before. - Hovering the mouse pointer over the log name reveals the full name - Clicking on the log line still brings up the detail dialog - You can select the text, and copy / paste it into a text file --------- Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>pull/3192/head
parent
1ae5fc6ec5
commit
794f5e9ee1
|
@ -222,6 +222,10 @@
|
||||||
<f7-icon v-else f7="exclamationmark_triangle" />
|
<f7-icon v-else f7="exclamationmark_triangle" />
|
||||||
</f7-link>
|
</f7-link>
|
||||||
<f7-link icon-f7="pencil" tooltip="Configure highlights" data-popup=".loghighlights-popup" class="popup-open" />
|
<f7-link icon-f7="pencil" tooltip="Configure highlights" data-popup=".loghighlights-popup" class="popup-open" />
|
||||||
|
<f7-segmented>
|
||||||
|
<f7-button outline small :active="!textMode" icon-f7="table" :icon-size="$theme.aurora ? 20 : 22" class="no-ripple" @click="setTextMode(false)" tooltip="Show logs in a table" />
|
||||||
|
<f7-button outline small :active="textMode" icon-f7="text_justifyleft" :icon-size="$theme.aurora ? 20 : 22" class="no-ripple" @click="setTextMode(true)" tooltip="Show logs as plain text" />
|
||||||
|
</f7-segmented>
|
||||||
<f7-link icon-f7="gear" tooltip="Configure logging" data-popup=".logsettings-popup" class="popup-open" />
|
<f7-link icon-f7="gear" tooltip="Configure logging" data-popup=".logsettings-popup" class="popup-open" />
|
||||||
</f7-toolbar>
|
</f7-toolbar>
|
||||||
|
|
||||||
|
@ -330,6 +334,38 @@
|
||||||
tr.trace
|
tr.trace
|
||||||
color rgb(112, 112, 112)
|
color rgb(112, 112, 112)
|
||||||
|
|
||||||
|
td.text
|
||||||
|
font-family monospace
|
||||||
|
font-size 0.9em
|
||||||
|
padding-left 4em
|
||||||
|
line-height 1.2em
|
||||||
|
color grey
|
||||||
|
span
|
||||||
|
margin-right 5px
|
||||||
|
.time
|
||||||
|
margin-left -3.2em
|
||||||
|
.level
|
||||||
|
width 3em
|
||||||
|
display inline-block
|
||||||
|
margin-right 0
|
||||||
|
.logger
|
||||||
|
width 20em
|
||||||
|
display inline-block
|
||||||
|
vertical-align middle
|
||||||
|
margin-right 0
|
||||||
|
.msg
|
||||||
|
font-weight bold
|
||||||
|
.error
|
||||||
|
color red
|
||||||
|
.warn
|
||||||
|
color orange
|
||||||
|
.info
|
||||||
|
color green
|
||||||
|
.debug
|
||||||
|
color teal
|
||||||
|
.trace
|
||||||
|
color teal
|
||||||
|
|
||||||
.disabled-link
|
.disabled-link
|
||||||
pointer-events none
|
pointer-events none
|
||||||
opacity 0.5
|
opacity 0.5
|
||||||
|
@ -398,6 +434,11 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Clipboard from 'v-clipboard'
|
||||||
|
|
||||||
|
Vue.use(Clipboard)
|
||||||
|
|
||||||
import MovablePopupMixin from '@/pages/settings/movable-popup-mixin'
|
import MovablePopupMixin from '@/pages/settings/movable-popup-mixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -419,6 +460,7 @@ export default {
|
||||||
showErrors: false,
|
showErrors: false,
|
||||||
loadingLoggers: true,
|
loadingLoggers: true,
|
||||||
loggerPackages: [],
|
loggerPackages: [],
|
||||||
|
textMode: localStorage.getItem('openhab.ui:logviewer.textMode') === 'true',
|
||||||
tableData: [],
|
tableData: [],
|
||||||
batchUpdatePending: false,
|
batchUpdatePending: false,
|
||||||
batchLogs: [],
|
batchLogs: [],
|
||||||
|
@ -554,7 +596,6 @@ export default {
|
||||||
},
|
},
|
||||||
renderEntry (entity) {
|
renderEntry (entity) {
|
||||||
let tr = document.createElement('tr')
|
let tr = document.createElement('tr')
|
||||||
tr.className = 'table-rows ' + entity.level.toLowerCase()
|
|
||||||
let icon = 'question_diamond'
|
let icon = 'question_diamond'
|
||||||
switch (entity.level) {
|
switch (entity.level) {
|
||||||
case 'TRACE':
|
case 'TRACE':
|
||||||
|
@ -573,10 +614,19 @@ export default {
|
||||||
icon = 'exclamationmark_octagon_fill'
|
icon = 'exclamationmark_octagon_fill'
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
tr.innerHTML = '<td class="sticky"><i class="icon f7-icons" style="font-size: 18px;">' + icon + `</i> ${entity.time}<span class="milliseconds">${entity.milliseconds}</span></td>` +
|
const levelLowerCased = entity.level.toLowerCase()
|
||||||
`<td class="level">${entity.level}</td>` +
|
if (this.textMode) {
|
||||||
`<td class="logger"><span class="logger">${entity.loggerName}</span></td>` +
|
tr.innerHTML = `<td class="text"><span class="time">${entity.time}${entity.milliseconds}</span>` +
|
||||||
`<td class="nowrap">${this.highlightText(entity.message)}</td>`
|
`[<span class="level ${levelLowerCased}">${entity.level}</span>] ` +
|
||||||
|
`[<span class="logger" title="${entity.loggerName}">${entity.loggerName}</span>] - ` +
|
||||||
|
`<span class="msg ${levelLowerCased}">${this.highlightText(entity.message)}</span></td>`
|
||||||
|
} else {
|
||||||
|
tr.className = 'table-rows ' + levelLowerCased
|
||||||
|
tr.innerHTML = '<td class="sticky"><i class="icon f7-icons" style="font-size: 18px;">' + icon + `</i> ${entity.time}<span class="milliseconds">${entity.milliseconds}</span></td>` +
|
||||||
|
`<td class="level">${entity.level}</td>` +
|
||||||
|
`<td class="logger"><span class="logger" title="${entity.loggerName}">${entity.loggerName}</span></td>` +
|
||||||
|
`<td class="nowrap">${this.highlightText(entity.message)}</td>`
|
||||||
|
}
|
||||||
tr.addEventListener('click', () => {
|
tr.addEventListener('click', () => {
|
||||||
this.onRowClick(entity.id)
|
this.onRowClick(entity.id)
|
||||||
})
|
})
|
||||||
|
@ -833,6 +883,21 @@ export default {
|
||||||
return [headers, ...rows].join('\n')
|
return [headers, ...rows].join('\n')
|
||||||
},
|
},
|
||||||
copyTableToClipboard () {
|
copyTableToClipboard () {
|
||||||
|
if (this.textMode) {
|
||||||
|
const logs = this.filteredTableData.map((log) => {
|
||||||
|
return `${log.time}${log.milliseconds} [${log.level}] [${log.loggerName}] - ${log.message}`
|
||||||
|
}).join('\n')
|
||||||
|
// v-clipboard works without https, but it can only copy plain text
|
||||||
|
if (this.$clipboard(logs)) {
|
||||||
|
this.$f7.toast.create({
|
||||||
|
text: 'Table copied as text to clipboard',
|
||||||
|
destroyOnClose: true,
|
||||||
|
closeTimeout: 2000
|
||||||
|
}).open()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const table = this.$refs.dataTable
|
const table = this.$refs.dataTable
|
||||||
if (!table) {
|
if (!table) {
|
||||||
return
|
return
|
||||||
|
@ -856,6 +921,7 @@ export default {
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$f7.toast.create({
|
this.$f7.toast.create({
|
||||||
text: 'Table copied as HTML to clipboard',
|
text: 'Table copied as HTML to clipboard',
|
||||||
|
destroyOnClose: true,
|
||||||
closeTimeout: 2000
|
closeTimeout: 2000
|
||||||
}).open()
|
}).open()
|
||||||
})
|
})
|
||||||
|
@ -863,6 +929,11 @@ export default {
|
||||||
console.error('Failed to copy table: ', err)
|
console.error('Failed to copy table: ', err)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
setTextMode (textModeEnabled) {
|
||||||
|
this.textMode = textModeEnabled
|
||||||
|
localStorage.setItem('openhab.ui:logviewer.textMode', this.textMode)
|
||||||
|
this.updateFilter()
|
||||||
|
},
|
||||||
prefilterHighlights () {
|
prefilterHighlights () {
|
||||||
this.activeHighlights.length = 0
|
this.activeHighlights.length = 0
|
||||||
for (const entry of this.highlightFilters) {
|
for (const entry of this.highlightFilters) {
|
||||||
|
|
Loading…
Reference in New Issue