mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 16:59:12 +00:00
feat(web): logs improvements (#284)
feat: add log searching feat: wrap parent container to add a scrollbar on overflow so it doesn't push the page lower with each message feat: switch to showing time instead of date+time
This commit is contained in:
parent
f836272fe6
commit
52fad1da95
3 changed files with 73 additions and 38 deletions
2
web/src/domain/react-table-config.d.ts
vendored
2
web/src/domain/react-table-config.d.ts
vendored
|
@ -64,7 +64,7 @@ declare module "react-table" {
|
|||
// note that having Record here allows you to add anything to the options, this matches the spirit of the
|
||||
// underlying js library, but might be cleaner if it's replaced by a more specific type that matches your
|
||||
// feature set, this is a safe default.
|
||||
Record<string, any> {}
|
||||
Record<string, unknown> {}
|
||||
|
||||
export interface Hooks<D extends Record<string, unknown> = Record<string, unknown>>
|
||||
extends UseExpandedHooks<D>,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { ExclamationIcon } from "@heroicons/react/solid";
|
||||
import format from "date-fns/format";
|
||||
import { DebounceInput } from "react-debounce-input";
|
||||
|
||||
import { APIClient } from "../api/APIClient";
|
||||
import { Checkbox } from "../components/Checkbox";
|
||||
|
@ -23,9 +25,12 @@ const LogColors: Record<LogLevel, string> = {
|
|||
|
||||
export const Logs = () => {
|
||||
const [settings, setSettings] = SettingsContext.use();
|
||||
|
||||
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [logs, setLogs] = useState<LogEvent[]>([]);
|
||||
const [searchFilter, setSearchFilter] = useState("");
|
||||
const [filteredLogs, setFilteredLogs] = useState<LogEvent[]>([]);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "auto" });
|
||||
|
@ -45,6 +50,21 @@ export const Logs = () => {
|
|||
return () => es.close();
|
||||
}, [setLogs, settings]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchFilter.length) {
|
||||
setFilteredLogs(logs);
|
||||
return;
|
||||
}
|
||||
|
||||
const newLogs: LogEvent[] = [];
|
||||
logs.forEach((log) => {
|
||||
if (log.message.indexOf(searchFilter) !== -1)
|
||||
newLogs.push(log);
|
||||
});
|
||||
|
||||
setFilteredLogs(newLogs);
|
||||
}, [logs, searchFilter]);
|
||||
|
||||
const onSetValue = (
|
||||
key: "scrollOnNewLog" | "indentLogLines" | "hideWrappedText",
|
||||
newValue: boolean
|
||||
|
@ -58,7 +78,7 @@ export const Logs = () => {
|
|||
<header className="py-10">
|
||||
<div className="max-w-screen-xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h1 className="text-3xl font-bold text-black dark:text-white">Logs</h1>
|
||||
<div className="flex mt-4 justify-center">
|
||||
<div className="flex justify-center">
|
||||
<ExclamationIcon
|
||||
className="h-5 w-5 text-yellow-400"
|
||||
aria-hidden="true"
|
||||
|
@ -69,8 +89,56 @@ export const Logs = () => {
|
|||
</header>
|
||||
<div className="max-w-screen-xl mx-auto pb-12 px-2 sm:px-4 lg:px-8">
|
||||
<div
|
||||
className="bg-white dark:bg-gray-800 rounded-lg shadow-lg px-2 sm:px-4 pb-3 sm:pb-4"
|
||||
className="bg-white dark:bg-gray-800 rounded-lg shadow-lg px-2 sm:px-4 pt-3 sm:pt-4"
|
||||
>
|
||||
<DebounceInput
|
||||
minLength={2}
|
||||
debounceTimeout={200}
|
||||
onChange={(event) => setSearchFilter(event.target.value.toLowerCase().trim())}
|
||||
id="filter"
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
className={classNames(
|
||||
"focus:ring-indigo-500 dark:focus:ring-blue-500 focus:border-indigo-500 dark:focus:border-blue-500 border-gray-300 dark:border-gray-700",
|
||||
"block w-full dark:bg-gray-800 shadow-sm dark:text-gray-100 sm:text-sm rounded-md"
|
||||
)}
|
||||
placeholder="Enter a string to filter logs by..."
|
||||
/>
|
||||
<div
|
||||
className="mt-2 overflow-y-auto p-2 rounded-lg h-[60vh] min-w-full bg-gray-100 dark:bg-gray-900 overflow-auto"
|
||||
>
|
||||
{filteredLogs.map((entry, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={classNames(
|
||||
settings.indentLogLines ? "grid justify-start grid-flow-col" : "",
|
||||
settings.hideWrappedText ? "truncate hover:text-ellipsis hover:whitespace-normal" : ""
|
||||
)}
|
||||
>
|
||||
<span
|
||||
title={entry.time}
|
||||
className="font-mono text-gray-500 dark:text-gray-600 mr-2 h-full"
|
||||
>
|
||||
{format(new Date(entry.time), "HH:mm:ss.SSS")}
|
||||
</span>
|
||||
{entry.level in LogColors ? (
|
||||
<span
|
||||
className={classNames(
|
||||
LogColors[entry.level as LogLevel],
|
||||
"font-mono font-semibold h-full"
|
||||
)}
|
||||
>
|
||||
{entry.level}
|
||||
{" "}
|
||||
</span>
|
||||
) : null}
|
||||
<span className="ml-2 text-black dark:text-gray-300">
|
||||
{entry.message}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
<Checkbox
|
||||
label="Scroll to bottom on new message"
|
||||
value={settings.scrollOnNewLog}
|
||||
|
@ -88,40 +156,6 @@ export const Logs = () => {
|
|||
value={settings.hideWrappedText}
|
||||
setValue={(newValue) => onSetValue("hideWrappedText", newValue)}
|
||||
/>
|
||||
<div
|
||||
className="overflow-y-auto p-2 rounded-lg min-h-[32rem] lg:min-h-[48rem] min-w-full bg-gray-100 dark:bg-gray-900"
|
||||
>
|
||||
{logs.map((a, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={classNames(
|
||||
settings.indentLogLines ? "grid justify-start grid-flow-col" : "",
|
||||
settings.hideWrappedText ? "truncate hover:text-ellipsis hover:whitespace-normal" : ""
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className="font-mono text-gray-500 dark:text-gray-600 mr-2 h-full"
|
||||
>
|
||||
{a.time}
|
||||
</span>
|
||||
{a.level in LogColors ? (
|
||||
<span
|
||||
className={classNames(
|
||||
LogColors[a.level as LogLevel],
|
||||
"font-mono font-semibold h-full"
|
||||
)}
|
||||
>
|
||||
{a.level}
|
||||
{" "}
|
||||
</span>
|
||||
) : null}
|
||||
<span className="ml-2 text-black dark:text-gray-300">
|
||||
{a.message}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue