mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
134 lines
3.7 KiB
TypeScript
134 lines
3.7 KiB
TypeScript
import React, { useEffect, useReducer, useState } from "react";
|
|
import { Form } from "react-bootstrap";
|
|
import * as GQL from "src/core/generated-graphql";
|
|
import { StashService } from "src/core/StashService";
|
|
|
|
function convertTime(logEntry: GQL.LogEntryDataFragment) {
|
|
function pad(val: number) {
|
|
let ret = val.toString();
|
|
if (val <= 9) {
|
|
ret = `0${ret}`;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
const date = new Date(logEntry.time);
|
|
const month = date.getMonth() + 1;
|
|
const day = date.getDate();
|
|
let dateStr = `${date.getFullYear()}-${pad(month)}-${pad(day)}`;
|
|
dateStr += ` ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(
|
|
date.getSeconds()
|
|
)}`;
|
|
|
|
return dateStr;
|
|
}
|
|
|
|
function levelClass(level: string) {
|
|
return level.toLowerCase().trim();
|
|
}
|
|
|
|
interface ILogElementProps {
|
|
logEntry: LogEntry;
|
|
}
|
|
|
|
const LogElement: React.FC<ILogElementProps> = ({ logEntry }) => {
|
|
// pad to maximum length of level enum
|
|
const level = logEntry.level.padEnd(GQL.LogLevel.Progress.length);
|
|
|
|
return (
|
|
<div className="row">
|
|
<span className="log-time">{logEntry.time}</span>
|
|
<span className={`${levelClass(logEntry.level)}`}>{level}</span>
|
|
<span className="col col-sm-9">{logEntry.message}</span>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
class LogEntry {
|
|
public time: string;
|
|
public level: string;
|
|
public message: string;
|
|
public id: string;
|
|
|
|
private static nextId: number = 0;
|
|
|
|
public constructor(logEntry: GQL.LogEntryDataFragment) {
|
|
this.time = convertTime(logEntry);
|
|
this.level = logEntry.level;
|
|
this.message = logEntry.message;
|
|
|
|
const id = LogEntry.nextId++;
|
|
this.id = id.toString();
|
|
}
|
|
}
|
|
|
|
// maximum number of log entries to display. Subsequent entries will truncate
|
|
// the list, dropping off the oldest entries first.
|
|
const MAX_LOG_ENTRIES = 200;
|
|
const logLevels = ["Debug", "Info", "Warning", "Error"];
|
|
|
|
const logReducer = (existingEntries:LogEntry[], newEntries:LogEntry[]) => (
|
|
[...newEntries.reverse(), ...existingEntries]
|
|
);
|
|
|
|
export const SettingsLogsPanel: React.FC = () => {
|
|
const { data, error } = StashService.useLoggingSubscribe();
|
|
const { data: existingData } = StashService.useLogs();
|
|
const [currentData, dispatchLogUpdate] = useReducer(logReducer, []);
|
|
const [logLevel, setLogLevel] = useState<string>("Info");
|
|
|
|
|
|
useEffect(() => {
|
|
const newData = (data?.loggingSubscribe ?? []).map((e) => new LogEntry(e));
|
|
dispatchLogUpdate(newData)
|
|
}, [data]);
|
|
|
|
const oldData = (existingData?.logs ?? []).map((e) => new LogEntry(e));
|
|
const filteredLogEntries = [...currentData, ...oldData]
|
|
.filter(filterByLogLevel)
|
|
.slice(0, MAX_LOG_ENTRIES);
|
|
|
|
const maybeRenderError = error ? (
|
|
<div className="error">Error connecting to log server: {error.message}</div>
|
|
) : (
|
|
""
|
|
);
|
|
|
|
function filterByLogLevel(logEntry: LogEntry) {
|
|
if (logLevel === "Debug") return true;
|
|
|
|
const logLevelIndex = logLevels.indexOf(logLevel);
|
|
const levelIndex = logLevels.indexOf(logEntry.level);
|
|
|
|
return levelIndex >= logLevelIndex;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<h4>Logs</h4>
|
|
<Form.Row id="log-level">
|
|
<Form.Label className="col-6 col-sm-2">Log Level</Form.Label>
|
|
<Form.Control
|
|
className="col-6 col-sm-2 input-control"
|
|
as="select"
|
|
defaultValue={logLevel}
|
|
onChange={(event) => setLogLevel(event.currentTarget.value)}
|
|
>
|
|
{logLevels.map((level) => (
|
|
<option key={level} value={level}>
|
|
{level}
|
|
</option>
|
|
))}
|
|
</Form.Control>
|
|
</Form.Row>
|
|
<div className="logs">
|
|
{maybeRenderError}
|
|
{filteredLogEntries.map((logEntry) => (
|
|
<LogElement logEntry={logEntry} key={logEntry.id} />
|
|
))}
|
|
</div>
|
|
</>
|
|
);
|
|
};
|