summaryrefslogtreecommitdiffhomepage
path: root/frontend
diff options
context:
space:
mode:
authorJayZed <[email protected]>2024-02-19 21:14:42 -0500
committerGitHub <[email protected]>2024-02-19 21:14:42 -0500
commitd5466fff2304e863e62fe2dfc62d9e88bdeb4068 (patch)
tree9c4bf6e41e5f45e6c09dcc56ecadf6a262ca4a4b /frontend
parentad8f116c78688ab038e834a8ad3a3b4c7bfee0c6 (diff)
downloadbazarr-d5466fff2304e863e62fe2dfc62d9e88bdeb4068.tar.gz
bazarr-d5466fff2304e863e62fe2dfc62d9e88bdeb4068.zip
Added log level/filter settings to Logs page
Diffstat (limited to 'frontend')
-rw-r--r--frontend/src/components/tables/PageControl.tsx7
-rw-r--r--frontend/src/components/tables/PageTable.tsx4
-rw-r--r--frontend/src/pages/Settings/General/index.tsx16
-rw-r--r--frontend/src/pages/Settings/components/LayoutModal.tsx99
-rw-r--r--frontend/src/pages/Settings/components/index.tsx1
-rw-r--r--frontend/src/pages/System/Logs/index.tsx84
-rw-r--r--frontend/src/types/settings.d.ts8
7 files changed, 215 insertions, 4 deletions
diff --git a/frontend/src/components/tables/PageControl.tsx b/frontend/src/components/tables/PageControl.tsx
index d00edcef6..0767593de 100644
--- a/frontend/src/components/tables/PageControl.tsx
+++ b/frontend/src/components/tables/PageControl.tsx
@@ -1,6 +1,6 @@
import { useIsLoading } from "@/contexts";
import { Group, Pagination, Text } from "@mantine/core";
-import { FunctionComponent } from "react";
+import { FunctionComponent, useEffect } from "react";
interface Props {
count: number;
index: number;
@@ -22,6 +22,11 @@ const PageControl: FunctionComponent<Props> = ({
const isLoading = useIsLoading();
+ // Jump to first page if total page count changes
+ useEffect(() => {
+ goto(0);
+ }, [total, goto]);
+
return (
<Group p={16} position="apart">
<Text size="sm">
diff --git a/frontend/src/components/tables/PageTable.tsx b/frontend/src/components/tables/PageTable.tsx
index fa958b28f..d84940857 100644
--- a/frontend/src/components/tables/PageTable.tsx
+++ b/frontend/src/components/tables/PageTable.tsx
@@ -1,4 +1,5 @@
import { ScrollToTop } from "@/utilities";
+import { usePageSize } from "@/utilities/storage";
import { useEffect } from "react";
import { usePagination, useTable } from "react-table";
import BaseTable from "./BaseTable";
@@ -22,6 +23,9 @@ export default function PageTable<T extends object>(props: Props<T>) {
...(plugins ?? [])
);
+ // use page size as specified in UI settings
+ instance.state.pageSize = usePageSize();
+
if (instanceRef) {
instanceRef.current = instance;
}
diff --git a/frontend/src/pages/Settings/General/index.tsx b/frontend/src/pages/Settings/General/index.tsx
index 96336a250..8cc5ea8c3 100644
--- a/frontend/src/pages/Settings/General/index.tsx
+++ b/frontend/src/pages/Settings/General/index.tsx
@@ -177,6 +177,22 @@ const SettingsGeneralView: FunctionComponent = () => {
<Section header="Logging">
<Check label="Debug" settingKey="settings-general-debug"></Check>
<Message>Debug logging should only be enabled temporarily</Message>
+ <Text
+ label="Include Filter"
+ settingKey="settings-log-include_filter"
+ ></Text>
+ <Text
+ label="Exclude Filter"
+ settingKey="settings-log-exclude_filter"
+ ></Text>
+ <Check
+ label="Use Regular Expressions (Regex)"
+ settingKey="settings-log-use_regex"
+ ></Check>
+ <Check
+ label="Ignore Case"
+ settingKey="settings-log-ignore_case"
+ ></Check>
</Section>
<Section header="Backups">
<File
diff --git a/frontend/src/pages/Settings/components/LayoutModal.tsx b/frontend/src/pages/Settings/components/LayoutModal.tsx
new file mode 100644
index 000000000..3ec074e09
--- /dev/null
+++ b/frontend/src/pages/Settings/components/LayoutModal.tsx
@@ -0,0 +1,99 @@
+import { useSettingsMutation, useSystemSettings } from "@/apis/hooks";
+import { LoadingProvider } from "@/contexts";
+import { useOnValueChange } from "@/utilities";
+import { LOG } from "@/utilities/console";
+import {
+ Button,
+ Container,
+ Divider,
+ Group,
+ LoadingOverlay,
+ Space,
+} from "@mantine/core";
+import { useForm } from "@mantine/form";
+import { FunctionComponent, ReactNode, useCallback, useMemo } from "react";
+import { FormContext, FormValues, runHooks } from "../utilities/FormValues";
+import { SettingsProvider } from "../utilities/SettingsProvider";
+
+interface Props {
+ children: ReactNode;
+ callbackModal: (value: boolean) => void;
+}
+
+const LayoutModal: FunctionComponent<Props> = (props) => {
+ const { children, callbackModal } = props;
+
+ const { data: settings, isLoading, isRefetching } = useSystemSettings();
+ const { mutate, isLoading: isMutating } = useSettingsMutation();
+
+ const form = useForm<FormValues>({
+ initialValues: {
+ settings: {},
+ hooks: {},
+ },
+ });
+
+ useOnValueChange(isRefetching, (value) => {
+ if (!value) {
+ form.reset();
+ }
+ });
+
+ const submit = useCallback(
+ (values: FormValues) => {
+ const { settings, hooks } = values;
+ if (Object.keys(settings).length > 0) {
+ const settingsToSubmit = { ...settings };
+ runHooks(hooks, settingsToSubmit);
+ LOG("info", "submitting settings", settingsToSubmit);
+ mutate(settingsToSubmit);
+ // wait for settings to be validated before callback
+ // let the user see the spinning indicator on the Save button before the modal closes
+ setTimeout(() => {
+ callbackModal(true);
+ }, 500);
+ }
+ },
+ [mutate, callbackModal]
+ );
+
+ const totalStagedCount = useMemo(() => {
+ return Object.keys(form.values.settings).length;
+ }, [form.values.settings]);
+
+ return (
+ <SettingsProvider value={settings ?? null}>
+ <LoadingProvider value={isLoading || isMutating}>
+ <form onSubmit={form.onSubmit(submit)} style={{ position: "relative" }}>
+ <LoadingOverlay visible={settings === undefined}></LoadingOverlay>
+ <FormContext.Provider value={form}>
+ <Container size="xl" mx={0}>
+ {children}
+ </Container>
+ </FormContext.Provider>
+ <Space h="md" />
+ <Divider></Divider>
+ <Space h="md" />
+ <Group position="right">
+ <Button
+ type="submit"
+ disabled={totalStagedCount === 0}
+ loading={isMutating}
+ >
+ Save
+ </Button>
+ <Button
+ onClick={() => {
+ callbackModal(true);
+ }}
+ >
+ Close
+ </Button>
+ </Group>
+ </form>
+ </LoadingProvider>
+ </SettingsProvider>
+ );
+};
+
+export default LayoutModal;
diff --git a/frontend/src/pages/Settings/components/index.tsx b/frontend/src/pages/Settings/components/index.tsx
index 15b60db29..9502f4366 100644
--- a/frontend/src/pages/Settings/components/index.tsx
+++ b/frontend/src/pages/Settings/components/index.tsx
@@ -65,6 +65,7 @@ export const URLTestButton: FunctionComponent<{
export * from "./Card";
export * from "./Layout";
export { default as Layout } from "./Layout";
+export { default as LayoutModal } from "./LayoutModal";
export * from "./Message";
export * from "./Section";
export * from "./collapse";
diff --git a/frontend/src/pages/System/Logs/index.tsx b/frontend/src/pages/System/Logs/index.tsx
index 8d12847d7..d77e102d8 100644
--- a/frontend/src/pages/System/Logs/index.tsx
+++ b/frontend/src/pages/System/Logs/index.tsx
@@ -1,10 +1,17 @@
-import { useDeleteLogs, useSystemLogs } from "@/apis/hooks";
+import { useDeleteLogs, useSystemLogs, useSystemSettings } from "@/apis/hooks";
import { Toolbox } from "@/components";
import { QueryOverlay } from "@/components/async";
+import { Check, LayoutModal, Message, Text } from "@/pages/Settings/components";
import { Environment } from "@/utilities";
-import { faDownload, faSync, faTrash } from "@fortawesome/free-solid-svg-icons";
-import { Container, Group } from "@mantine/core";
+import {
+ faDownload,
+ faFilter,
+ faSync,
+ faTrash,
+} from "@fortawesome/free-solid-svg-icons";
+import { Badge, Container, Group, Stack } from "@mantine/core";
import { useDocumentTitle } from "@mantine/hooks";
+import { useModals } from "@mantine/modals";
import { FunctionComponent, useCallback } from "react";
import Table from "./table";
@@ -20,6 +27,61 @@ const SystemLogsView: FunctionComponent = () => {
useDocumentTitle("Logs - Bazarr (System)");
+ const { data: settings } = useSystemSettings();
+ const modals = useModals();
+
+ const suffix = () => {
+ const include = settings?.log.include_filter;
+ const exclude = settings?.log.exclude_filter;
+ const includeIndex = include !== "" && include !== undefined ? 1 : 0;
+ const excludeIndex = exclude !== "" && exclude !== undefined ? 1 : 0;
+ const filters = [
+ ["", "I"],
+ ["E", "I/E"],
+ ];
+ const filterStr = filters[excludeIndex][includeIndex];
+ const debugStr = settings?.general.debug ? "Debug" : "";
+ const spaceStr = debugStr !== "" && filterStr !== "" ? " " : "";
+ const suffixStr = debugStr + spaceStr + filterStr;
+ return suffixStr;
+ };
+
+ const openFilterModal = () => {
+ const callbackModal = (close: boolean) => {
+ if (close) {
+ modals.closeModal(id);
+ }
+ };
+
+ const id = modals.openModal({
+ title: "Set Log Debug and Filter Options",
+ children: (
+ <LayoutModal callbackModal={callbackModal}>
+ <Stack>
+ <Check label="Debug" settingKey="settings-general-debug"></Check>
+ <Message>Debug logging should only be enabled temporarily</Message>
+ <Text
+ label="Include Filter"
+ settingKey="settings-log-include_filter"
+ ></Text>
+ <Text
+ label="Exclude Filter"
+ settingKey="settings-log-exclude_filter"
+ ></Text>
+ <Check
+ label="Use Regular Expressions (Regex)"
+ settingKey="settings-log-use_regex"
+ ></Check>
+ <Check
+ label="Ignore Case"
+ settingKey="settings-log-ignore_case"
+ ></Check>
+ </Stack>
+ </LayoutModal>
+ ),
+ });
+ };
+
return (
<Container fluid px={0}>
<QueryOverlay result={logs}>
@@ -42,6 +104,22 @@ const SystemLogsView: FunctionComponent = () => {
>
Empty
</Toolbox.Button>
+ <Toolbox.Button
+ loading={isLoading}
+ icon={faFilter}
+ onClick={openFilterModal}
+ rightIcon={
+ suffix() !== "" ? (
+ <Badge size="xs" radius="sm">
+ {suffix()}
+ </Badge>
+ ) : (
+ <></>
+ )
+ }
+ >
+ Filter
+ </Toolbox.Button>
</Group>
</Toolbox>
<Table logs={data ?? []}></Table>
diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts
index d88489a0e..d46a9734e 100644
--- a/frontend/src/types/settings.d.ts
+++ b/frontend/src/types/settings.d.ts
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-empty-interface */
interface Settings {
general: Settings.General;
+ log: Settings.Log;
proxy: Settings.Proxy;
auth: Settings.Auth;
subsync: Settings.Subsync;
@@ -82,6 +83,13 @@ declare namespace Settings {
wanted_search_frequency_movie: number;
}
+ interface Log {
+ include_filter: string;
+ exclude_filter: string;
+ ignore_case: boolean;
+ use_regex: boolean;
+ }
+
interface Proxy {
exclude: string[];
type?: string;