11import { Suspense , useState } from "react" ;
2- import { Spinner , Select } from "@fluentui/react-components" ;
2+ import {
3+ Spinner ,
4+ Select ,
5+ makeStyles ,
6+ mergeClasses ,
7+ tokens ,
8+ } from "@fluentui/react-components" ;
39import { useSuspenseQuery } from "@tanstack/react-query" ;
410
511import { LOG_LEVELS , type ClientIdType } from "../../api/urbackupserver" ;
612import { urbackupServer } from "../../App" ;
713import { SelectClientCombobox } from "../../components/SelectClientCombobox" ;
814import { LogsTable } from "./LogsTable" ;
915import { TableWrapper } from "../../components/TableWrapper" ;
16+ import { LiveLog } from "./LiveLog" ;
17+ import { LogReports } from "./LogReports" ;
1018
1119const FORMATTED_LOG_LEVELS = {
1220 INFO : "All" ,
1321 WARNING : "Warnings" ,
1422 ERROR : "Errors" ,
1523} as const ;
1624
25+ const useStyles = makeStyles ( {
26+ root : {
27+ display : "grid" ,
28+ gap : tokens . spacingVerticalXXL ,
29+ gridTemplateColumns : "1fr 320px" ,
30+ alignItems : "start" ,
31+ // Adjust height to match client log tables with breadcrumbs
32+ marginBlockStart : "-7px" ,
33+ } ,
34+ reports : {
35+ display : "flex" ,
36+ flexDirection : "column" ,
37+ background : tokens . colorNeutralCardBackground ,
38+ padding : tokens . spacingHorizontalL ,
39+ borderRadius : tokens . borderRadiusLarge ,
40+ height : "min-content" ,
41+ } ,
42+ } ) ;
43+
1744export function ClientLogs ( ) {
1845 const [ selectedClientId , setSelectedClientId ] = useState <
1946 ClientIdType | undefined
@@ -23,6 +50,8 @@ export function ClientLogs() {
2350 ( typeof LOG_LEVELS ) [ keyof typeof LOG_LEVELS ]
2451 > ( LOG_LEVELS . ERROR ) ;
2552
53+ const classes = useStyles ( ) ;
54+
2655 // Used for fetching clients list for logs
2756 const logsResult = useSuspenseQuery ( {
2857 queryKey : [ "logs" ] ,
@@ -32,31 +61,45 @@ export function ClientLogs() {
3261 const { clients } = logsResult . data ;
3362
3463 return (
35- < TableWrapper >
36- < h3 > Logs</ h3 >
37- < div className = "cluster" >
38- < SelectClientCombobox
39- clients = { clients }
40- onSelect = { ( id ) => setSelectedClientId ( Number ( id ) ) }
41- />
42- < div className = "cluster" data-spacing = "s" >
43- Filter
44- < Select
45- id = "log-level"
46- defaultValue = { logLevel }
47- onChange = { ( _ , data ) => setLogLevel ( + data . value as typeof logLevel ) }
48- >
49- { Object . entries ( LOG_LEVELS ) . map ( ( [ k , v ] ) => (
50- < option key = { k } value = { v } >
51- { FORMATTED_LOG_LEVELS [ k as keyof typeof LOG_LEVELS ] }
52- </ option >
53- ) ) }
54- </ Select >
64+ < div className = { classes . root } >
65+ < TableWrapper >
66+ < div className = "repel" >
67+ < h3 > Logs</ h3 >
68+ < LiveLog clients = { clients } > Open Live Log</ LiveLog >
69+ </ div >
70+ < div className = "cluster" >
71+ < SelectClientCombobox
72+ clients = { clients }
73+ onSelect = { ( id ) => setSelectedClientId ( Number ( id ) ) }
74+ />
75+ < div className = "cluster" data-spacing = "s" >
76+ Filter
77+ < Select
78+ id = "log-level"
79+ defaultValue = { logLevel }
80+ onChange = { ( _ , data ) =>
81+ setLogLevel ( + data . value as typeof logLevel )
82+ }
83+ >
84+ { Object . entries ( LOG_LEVELS ) . map ( ( [ k , v ] ) => (
85+ < option key = { k } value = { v } >
86+ { FORMATTED_LOG_LEVELS [ k as keyof typeof LOG_LEVELS ] }
87+ </ option >
88+ ) ) }
89+ </ Select >
90+ </ div >
5591 </ div >
92+ < Suspense fallback = { < Spinner /> } >
93+ < LogsTable selectedClientId = { selectedClientId } logLevel = { logLevel } />
94+ </ Suspense >
95+ </ TableWrapper >
96+ < div className = { mergeClasses ( classes . reports , "flow" ) } >
97+ < h4 > Reports</ h4 >
98+ < p > Automatically send reports to emails.</ p >
99+ < Suspense fallback = { < Spinner /> } >
100+ < LogReports />
101+ </ Suspense >
56102 </ div >
57- < Suspense fallback = { < Spinner /> } >
58- < LogsTable selectedClientId = { selectedClientId } logLevel = { logLevel } />
59- </ Suspense >
60- </ TableWrapper >
103+ </ div >
61104 ) ;
62105}
0 commit comments