Skip to content

Commit

Permalink
[111] Add QOL visual effects to the Logs page
Browse files Browse the repository at this point in the history
- Add dynamic links for Fonts, Templates, Series, Connections, and Fonts parsed from log messages
- Add formatting for redacted messages
- Highlight search text
- Format code log messages with monospace fonts, and preserved whitespace
  • Loading branch information
CollinHeist committed Jul 9, 2024
1 parent e0c63d3 commit 6bb6c56
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 33 deletions.
22 changes: 21 additions & 1 deletion app/templates/css/logs.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,29 @@
-webkit-box-orient: vertical;
}

/* Formatting for code (traceback) messages */
#log-data td.code[data-value="message"] {
/* Use a monospace font so text alignment is preserved */
font-family: monospace;
/* Preserve spaces so traceback boxes and lines are kept */
white-space: preserve;
/* Show up to 10 lines, not 5 */
line-clamp: 10;
-webkit-line-clamp: 10;
}

/* Center align table on mobile */
@media (max-width: 768px) {
table th, table td {
text-align: center !important;
}
}
}

/* Stylize "redacted" text */
span.redacted.text:not(:hover, :focus) {
/* Hide the text */
color: transparent;
/* Add black highlight over text */
background-color: #1a1a1a;
border-radius: 4px;
}
37 changes: 18 additions & 19 deletions app/templates/js/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,20 @@ function formatFastAPIError(errorResponse) {
* snakeToTitleCase('frame_width') // returns 'Frame Width'
*/
const snakeToTitleCase = (snakeStr) => {
console.log(snakeStr);
return `${snakeStr}`
.split('_')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ')
};

/** @type {string} Formatted error text. */
const formattedErrors = errorResponse.detail.map(detail => {
// String-only detail
if (typeof detail === 'string') {
return detail;
}

// Parse each location of the error
if (detail.loc && Array.isArray(detail.loc)) {
const location = detail.loc.map(snakeToTitleCase).join(' -> ').trim();
// Do not display "root" level locations, this will confuse people
Expand Down Expand Up @@ -169,7 +170,8 @@ function showErrorToast({title, message, response, displayTime=7500}) {
* @param {string} [args.title] - Title of the toast.
* @param {string} [args.message] - Message of the toast - only displayed if
* args.response is undefined.
* @param {number} [args.displayTime=1000] - How long (in ms) to display the toast.
* @param {number} [args.displayTime=1000] - How long (in ms) to display the
* toast.
*/
function showInfoToast(args) {
if (typeof args === 'string') {
Expand All @@ -186,14 +188,13 @@ function showInfoToast(args) {
}

/**
* Get the list of template values (for a $.dropdown) based on the given
* IDs.
* @param {int[]} activeIds - Template IDs which are active and to include
* in the return.
* @param {Object[]} availableTemplates - List of all the available
* Template objects which should be filtered.
* @returns {DropdownValue[]} List of values which can be used in the
* dropdown initialization for the given Template IDs.
* Get the list of template values (for a $.dropdown) based on the given IDs.
* @param {int[]} activeIds - Template IDs which are active and to include in
* the return.
* @param {Object[]} availableTemplates - List of all the available Template
* objects which should be filtered.
* @returns {DropdownValue[]} List of values which can be used in the dropdown
* initialization for the given Template IDs.
*/
function getActiveTemplates(activeIds, availableTemplates) {
let values = [];
Expand Down Expand Up @@ -226,10 +227,10 @@ function getActiveTemplates(activeIds, availableTemplates) {
*
* @param {int} pageNumber - Page number of the element to create.
* @param {string} pageText - Text to display within the element.
* @param {bool} active - Whether this element should be created as active
* and disabled.
* @param {function} navigateFunction - Function to call when this element
* is clicked.
* @param {bool} active - Whether this element should be created as active and
* disabled.
* @param {function} navigateFunction - Function to call when this element is
* clicked.
* @returns {HTMLElement} Created element for use in a pagination menu.
*/
function createPageElement(pageNumber, pageText, active = false, navigateFunction) {
Expand All @@ -251,15 +252,14 @@ function createPageElement(pageNumber, pageText, active = false, navigateFunctio
*
* @param {string} [args.paginationElementId] - DOM Element ID of the pagination
* menu to update.
* @param {function} [args.navigateFunction] - Function to call when a
* page button is clicked.
* @param {function} [args.navigateFunction] - Function to call when a page
* button is clicked.
* @param {number} [args.page=1] - Current page number. Defaults to 1.
* @param {number} [args.pages=1] - Total number of pages. Defaults to 1.
* @param {?number} [args.amountVisible] - Total number of page buttons to make
* visible. If undefined, then the amount is determined by the element width.
* @param {boolean} [args.hideIfSinglePage=false] - Whether to hide the
* pagination menu if there is only a single page.
* @returns
*/
function updatePagination(args) {
let {
Expand Down Expand Up @@ -598,8 +598,7 @@ function timeDiffString(previousRun) {
* @param {string} str - The input string to convert to title case.
* @returns {string} The input string converted to title case.
* @example
* // returns "I Love JavaScript"
* toTitleCase("i love JavaScript");
* toTitleCase("i love JavaScript"); // returns "I Love JavaScript"
*/
function toTitleCase(str) {
return str.replace(/(?:^|\s)\w/g, function(match) {
Expand Down
64 changes: 53 additions & 11 deletions app/templates/js/logs.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import {LogEntryPage, LogLevel} from './.types.js';
{% endif %}

/**
*
* Parse a Date from the given file name.
* @param {string} name - Name to extract the Date from.
* @returns {Date} parsed from the given name.
*/
function parseDate(name) {
const pattern = /(\d{4}-\d{2}-\d{2})_(\d{2}-\d{2}-\d{2})/;

try {
const [, datePart, timePart] = name.match(pattern);
const [year, month, day] = datePart.split("-");
Expand All @@ -18,7 +17,6 @@ function parseDate(name) {
} catch {
return new Date();
}

}

/**
Expand All @@ -27,7 +25,6 @@ function parseDate(name) {
* dropdown.
*/
function updateMessageLevel(level) {
// Uppercase first letter of level
const newLevel = level.toUpperCase();
$('.dropdown[data-value="level"]').dropdown('set text', newLevel);
$('.dropdown[data-value="level"]').dropdown('set selected', newLevel);
Expand Down Expand Up @@ -65,10 +62,46 @@ function appendContextID(id) {
}
}

/** Reset the filter form. */
const resetForm = () => $('#log-filters').form('clear');

/**
* Reset the filter form.
* Parse the given message into navigation links around "objects" like Series,
* Templates, Syncs, etc. Also stylizes redacted messages.
* @param {string} message Message to parse for links to objects.
* @param {string} searchText Text was used to filter log messages with. Used in
* text highlighting.
* @returns {string} Modified message.
*/
const resetForm = () => $('#log-filters').form('clear');
function parseLinks(message, searchText='') {
return message
.replace(
/Series\[(\d+)\]/g,
(match, seriesID) => `<a href="/series/${seriesID}">${match}</a>`
).replace(
/Task\[\w+\]/g,
(match) => `<a href="/scheduler">${match}</a>`
).replace(
/Sync\[\d+\]/g,
(match) => `<a href="/sync">${match}</a>`
).replace(
/(Emby|Jellyfin|Plex|Sonarr|TMDb|TVDb)(Connection|Interface)\[\d+\]/g,
(match) => `<a href="/connections">${match}</a>`
).replace(
/Template\[\d+\]/g,
(match) => `<a href="/card-templates">${match}</a>`
).replace(
/Font\[(\d+)\]/g,
(match, fontID) => `<a href="/fonts#font-id${fontID}">${match}</a>`
).replace(
/\[REDACTED\]/g,
() => `<span class="redacted text">[REDACTED]</span>`,
).replace(
searchText,
`<span class="ui yellow text">${searchText}</span>`,
)
;
}

/**
* Submit an API request to query for the given page of logs. If successful,
Expand Down Expand Up @@ -110,10 +143,18 @@ function queryForLogs(page=1) {
}
row.querySelector('[data-value="context_id"]').innerText = message.context_id;

row.querySelector('[data-value="message"]').innerText = message.exception?.traceback
? message.message + '\n\n' + message.exception.traceback
: message.message
;
if (message.exception?.traceback) {
row.querySelector('[data-value="message"]').classList.add('code');
row.querySelector('[data-value="message"]').innerText = message.message + '\n\n' + message.exception.traceback;
} else if (message.message.startsWith('Internal Server Error') || message.message.includes('Traceback (most recent call last)')) {
row.querySelector('[data-value="message"]').classList.add('code');
row.querySelector('[data-value="message"]').innerText = message.message;
} else {
row.querySelector('[data-value="message"]').innerHTML = parseLinks(
message.message,
document.querySelector('input[name="contains"]').value,
);
}

// On click of log level, update filter level
row.querySelector('[data-value="level"]').onclick = () => updateMessageLevel(message.level);
Expand All @@ -129,6 +170,7 @@ function queryForLogs(page=1) {

// Add rows to page
document.getElementById('log-data').replaceChildren(...rows);
document.getElementById('log-table').scrollIntoView({behavior: 'smooth', block: 'start'});

// Update pagination
updatePagination({
Expand Down Expand Up @@ -217,4 +259,4 @@ function initAll() {
datetime: 'YYYY-MM-DDTHH:mm:ss', // ISO 8601
}
});
}
}
2 changes: 1 addition & 1 deletion app/templates/logs.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ <h1 class="ui header">Logs</h1>
</form>

<!-- Logs -->
<table class="ui striped celled compact table ">
<table class="ui striped celled compact table" id="log-table">
<thead>
<tr>
<th class="center aligned collapsing">Level</th>
Expand Down
2 changes: 1 addition & 1 deletion modules/ref/version_webui
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.0-alpha.10.1-webui110
v2.0-alpha.10.1-webui111

0 comments on commit 6bb6c56

Please sign in to comment.