ui: add jump and sync for backend logs
This commit is contained in:
parent
36edfd8413
commit
fc63e4d83d
2 changed files with 51 additions and 42 deletions
|
|
@ -2,6 +2,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||||
import { Segmented } from 'antd';
|
import { Segmented } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { VList, VListHandle } from 'virtua';
|
import { VList, VListHandle } from 'virtua';
|
||||||
|
import { PlayerContext } from "App/components/Session/playerContext";
|
||||||
import { processLog, UnifiedLog } from './utils';
|
import { processLog, UnifiedLog } from './utils';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import { useStore } from 'App/mstore';
|
import { useStore } from 'App/mstore';
|
||||||
|
|
@ -32,6 +33,7 @@ async function fetchLogs(
|
||||||
const logsResp = await fetch(json.url)
|
const logsResp = await fetch(json.url)
|
||||||
if (logsResp.ok) {
|
if (logsResp.ok) {
|
||||||
const logJson = await logsResp.json()
|
const logJson = await logsResp.json()
|
||||||
|
if (logJson.length === 0) return []
|
||||||
return processLog(logJson)
|
return processLog(logJson)
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Failed to fetch logs')
|
throw new Error('Failed to fetch logs')
|
||||||
|
|
@ -59,16 +61,7 @@ function BackendLogsPanel() {
|
||||||
enabled: tab !== null,
|
enabled: tab !== null,
|
||||||
retry: 3,
|
retry: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(isError, isPending, isSuccess)
|
|
||||||
const [filter, setFilter] = React.useState('');
|
const [filter, setFilter] = React.useState('');
|
||||||
const _list = React.useRef<VListHandle>(null);
|
|
||||||
const activeIndex = 1;
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (_list.current) {
|
|
||||||
_list.current.scrollToIndex(activeIndex);
|
|
||||||
}
|
|
||||||
}, [activeIndex]);
|
|
||||||
|
|
||||||
const onFilterChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const onFilterChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setFilter(e.target.value);
|
setFilter(e.target.value);
|
||||||
|
|
@ -122,40 +115,44 @@ function BackendLogsPanel() {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{isSuccess ? (
|
{isSuccess ? (
|
||||||
<>
|
<LogsTable data={data} />
|
||||||
<TableHeader size={data.length} />
|
|
||||||
<VList ref={_list} count={testLogs.length}>
|
|
||||||
{data.map((log, index) => (
|
|
||||||
<LogRow key={index} log={log} />
|
|
||||||
))}
|
|
||||||
</VList>
|
|
||||||
</>
|
|
||||||
) : null}
|
) : null}
|
||||||
</BottomBlock.Content>
|
</BottomBlock.Content>
|
||||||
</BottomBlock>
|
</BottomBlock>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const testLogs = [
|
const LogsTable = observer(({ data }: { data: UnifiedLog[] }) => {
|
||||||
{
|
const { store, player } = React.useContext(PlayerContext);
|
||||||
key: 1,
|
const time = store.get().time;
|
||||||
timestamp: '2021-09-01 12:00:00',
|
const sessionStart = store.get().sessionStart;
|
||||||
status: 'INFO',
|
const _list = React.useRef<VListHandle>(null);
|
||||||
content: 'This is a test log',
|
const activeIndex = React.useMemo(() => {
|
||||||
},
|
const currTs = time + sessionStart;
|
||||||
{
|
const index = data.findIndex(
|
||||||
key: 2,
|
(log) => log.timestamp !== 'N/A' ? new Date(log.timestamp).getTime() >= currTs : false
|
||||||
timestamp: '2021-09-01 12:00:00',
|
);
|
||||||
status: 'WARN',
|
return index === -1 ? data.length - 1 : index;
|
||||||
content: 'This is a test log',
|
}, [time, data.length]);
|
||||||
},
|
React.useEffect(() => {
|
||||||
{
|
if (_list.current) {
|
||||||
key: 3,
|
_list.current.scrollToIndex(activeIndex);
|
||||||
timestamp: '2021-09-01 12:00:00',
|
}
|
||||||
status: 'ERROR',
|
}, [activeIndex]);
|
||||||
content:
|
|
||||||
'This is a test log that is very long and should be truncated to fit in the table cell and it will be displayed later in a separate thing when clicked on a row because its so long you never gonna give htem up or alskjhaskfjhqwfhwekfqwfjkqlwhfkjqhflqkwjhefqwklfehqwlkfjhqwlkjfhqwe \n kjhdafskjfhlqkwjhfwelefkhwqlkqehfkqlwehfkqwhefkqhwefkjqwhf',
|
const onJump = (ts: number) => {
|
||||||
},
|
player.jump(ts - sessionStart);
|
||||||
];
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<TableHeader size={data.length} />
|
||||||
|
<VList ref={_list} count={data.length}>
|
||||||
|
{data.map((log, index) => (
|
||||||
|
<LogRow key={index} isActive={index === activeIndex} log={log} onJump={onJump} />
|
||||||
|
))}
|
||||||
|
</VList>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
export default observer(BackendLogsPanel);
|
export default observer(BackendLogsPanel);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { Button } from 'antd';
|
||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import { getDateFromString } from 'App/date';
|
import { getDateFromString } from 'App/date';
|
||||||
|
import JumpButton from 'App/components/shared/DevTools/JumpButton';
|
||||||
|
|
||||||
export function TableHeader({ size }: { size: number }) {
|
export function TableHeader({ size }: { size: number }) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -28,8 +29,12 @@ export function TableHeader({ size }: { size: number }) {
|
||||||
|
|
||||||
export function LogRow({
|
export function LogRow({
|
||||||
log,
|
log,
|
||||||
|
onJump,
|
||||||
|
isActive,
|
||||||
}: {
|
}: {
|
||||||
log: { timestamp: string; status: string; content: string };
|
log: { timestamp: string; status: string; content: string };
|
||||||
|
onJump: (ts: number) => void;
|
||||||
|
isActive?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const [isExpanded, setIsExpanded] = React.useState(false);
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
||||||
const bg = (status: string) => {
|
const bg = (status: string) => {
|
||||||
|
|
@ -54,13 +59,16 @@ export function LogRow({
|
||||||
return 'border-l border-l-4 border-gray-lighter';
|
return 'border-l border-l-4 border-gray-lighter';
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className={'code-font'}>
|
<div
|
||||||
|
className={'code-font relative group'}
|
||||||
|
>
|
||||||
|
<JumpButton onClick={() => onJump(new Date(log.timestamp).getTime())} />
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'text-sm grid items-center py-2 px-4',
|
'text-sm grid items-center py-2 px-4',
|
||||||
'cursor-pointer border-b border-b-gray-light last:border-b-0',
|
'cursor-pointer border-b border-b-gray-light last:border-b-0',
|
||||||
border(log.status),
|
border(log.status),
|
||||||
bg(log.status)
|
isActive ? 'bg-gray-lightest' : bg(log.status)
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
gridTemplateColumns: 'repeat(14, minmax(0, 1fr))',
|
gridTemplateColumns: 'repeat(14, minmax(0, 1fr))',
|
||||||
|
|
@ -90,10 +98,14 @@ export function LogRow({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isExpanded ? (
|
{isExpanded ? (
|
||||||
<div className={'rounded bg-gray-lightest px-4 py-2 relative mx-4 my-2'}>
|
<div
|
||||||
|
className={'rounded bg-gray-lightest px-4 py-2 relative mx-4 my-2'}
|
||||||
|
>
|
||||||
{log.content.split('\n').map((line, index) => (
|
{log.content.split('\n').map((line, index) => (
|
||||||
<div key={index} className={'flex items-start gap-2'}>
|
<div key={index} className={'flex items-start gap-2'}>
|
||||||
<div className={'border-r border-r-gray-light pr-2 select-none'}>{index}</div>
|
<div className={'border-r border-r-gray-light pr-2 select-none'}>
|
||||||
|
{index}
|
||||||
|
</div>
|
||||||
<div className={'whitespace-pre-wrap'}>{line}</div>
|
<div className={'whitespace-pre-wrap'}>{line}</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue