Load user logs (#809)

This commit is contained in:
Piotr Rogowski 2022-10-18 21:40:53 +02:00 committed by GitHub
parent f195ad6d3a
commit a77d1e790b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 29 deletions

View File

@ -148,6 +148,7 @@ const App = ({ ui, navigation, tuneData }: { ui: UIState, navigation: Navigation
<Route path={Routes.TUNE_ROOT} element={<ContentFor element={<Info />} />} />
<Route path={`${Routes.TUNE_TUNE}/*`} element={<ContentFor marginLeft={margin} element={<Tune />} />} />
<Route path={Routes.TUNE_LOGS} element={<ContentFor marginLeft={margin} element={<Logs />} />} />
<Route path={Routes.TUNE_LOGS_FILE} element={<ContentFor marginLeft={margin} element={<Logs />} />} />
<Route path={Routes.TUNE_DIAGNOSE} element={<ContentFor marginLeft={margin} element={<Diagnose />} />} />
<Route path={`${Routes.UPLOAD}/*`} element={<ContentFor element={<Upload />} />} />

View File

@ -67,6 +67,7 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => {
const hubPathMatch = useMatch(Routes.HUB);
const tuneRootMatch = useMatch(`${Routes.TUNE_ROOT}/*`);
const tuneTuneMatch = useMatch(`${Routes.TUNE_TUNE}/*`);
const tuneLogMatch = useMatch(`${Routes.TUNE_LOGS}/*`);
const tabMatch = useMatch(`${Routes.TUNE_TAB}/*`);
const uploadMatch = useMatch(Routes.UPLOAD);
const hubMatch = useMatch(Routes.HUB);
@ -95,7 +96,7 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => {
<Col span={16} md={16} sm={16}>
<Radio.Group
key={pathname}
defaultValue={tuneTuneMatch?.pathnameBase || tabMatch?.pathname || tuneRootMatch?.pathname || hubPathMatch?.pathname}
defaultValue={tuneLogMatch?.pathnameBase || tuneTuneMatch?.pathnameBase || tabMatch?.pathname || tuneRootMatch?.pathname || hubPathMatch?.pathname}
optionType="button"
buttonStyle="solid"
onChange={(e) => navigate(e.target.value)}
@ -132,7 +133,7 @@ const TopBar = ({ tuneId }: { tuneId: string | null }) => {
</Radio.Button>
</Radio.Group>
</Col>
), [buildTuneUrl, lg, navigate, pathname, hubPathMatch?.pathname, tabMatch?.pathname, tuneRootMatch?.pathname, tuneTuneMatch?.pathnameBase]);
), [pathname, tuneTuneMatch?.pathnameBase, tabMatch?.pathname, tuneRootMatch?.pathname, hubPathMatch?.pathname, tuneLogMatch?.pathnameBase, buildTuneUrl, lg, navigate]);
const rightMenuColProps = tuneId ? {
span: 8,

View File

@ -23,12 +23,10 @@ import * as Sentry from '@sentry/browser';
import useBreakpoint from 'antd/lib/grid/hooks/useBreakpoint';
import { connect } from 'react-redux';
import PerfectScrollbar from 'react-perfect-scrollbar';
import {
Config,
Logs,
} from '@hyper-tuner/types';
import {
AppState,
ConfigState,
LogsState,
UIState,
} from '../types/state';
import {
@ -64,7 +62,7 @@ const margin = 30;
const sidebarWidth = 250;
const minCanvasHeightInner = 600;
const Diagnose = ({ ui, config, loadedLogs }: { ui: UIState, config: Config, loadedLogs: Logs }) => {
const Diagnose = ({ ui, config, loadedLogs }: { ui: UIState, config: ConfigState, loadedLogs: LogsState }) => {
const { lg } = useBreakpoint();
const { Sider } = Layout;
const [progress, setProgress] = useState(0);
@ -147,7 +145,7 @@ const Diagnose = ({ ui, config, loadedLogs }: { ui: UIState, config: Config, loa
return (
<>
<Sider {...(siderProps as any)} className="app-sidebar">
{!logs && !loadedLogs.length ?
{!logs && !(loadedLogs.logs || []).length ?
<Loader />
:
!ui.sidebarCollapsed &&

View File

@ -1,3 +1,9 @@
import {
Link,
generatePath,
useMatch,
useNavigate,
} from 'react-router-dom';
import {
useCallback,
useEffect,
@ -27,7 +33,6 @@ import { connect } from 'react-redux';
import { Result as ParserResult } from 'mlg-converter/dist/types';
import PerfectScrollbar from 'react-perfect-scrollbar';
import {
Config,
OutputChannel,
Logs as LogsType,
DatalogEntry,
@ -47,12 +52,15 @@ import {
} from '../utils/tune/expression';
import {
AppState,
ConfigState,
LogsState,
TuneDataState,
UIState,
} from '../types/state';
import Loader from '../components/Loader';
import { Colors } from '../utils/colors';
import { TunesRecordFull } from '../types/dbData';
import useServerStorage from '../hooks/useServerStorage';
import { Routes } from '../routes';
const { Content } = Layout;
const { Step } = Steps;
@ -77,9 +85,9 @@ const Logs = ({
tuneData,
}: {
ui: UIState,
config: Config,
loadedLogs: LogsType,
tuneData: TunesRecordFull,
config: ConfigState,
loadedLogs: LogsState,
tuneData: TuneDataState,
}) => {
const { lg } = useBreakpoint();
const { Sider } = Layout;
@ -95,6 +103,9 @@ const Logs = ({
const [canvasWidth, setCanvasWidth] = useState(0);
const [canvasHeight, setCanvasHeight] = useState(0);
const { fetchLogFileWithProgress } = useServerStorage();
const routeMatch = useMatch(Routes.TUNE_LOGS_FILE);
const navigate = useNavigate();
const calculateCanvasSize = useCallback(() => {
setCanvasWidth((contentRef.current?.clientWidth || 0) - margin);
@ -157,15 +168,12 @@ const Logs = ({
const worker = new MlgParserWorker();
const controller = new AbortController();
const { signal } = controller;
const loadData = async () => {
const firstLogFile = (tuneData.logFiles || [])[0];
if (!firstLogFile) {
return;
}
const loadData = async () => {
const logFileName = routeMatch?.params.fileName!;
try {
const raw = await fetchLogFileWithProgress(tuneData.id, firstLogFile, (percent, total, edge) => {
const raw = await fetchLogFileWithProgress(tuneData.id, logFileName, (percent, total, edge) => {
setProgress(percent);
setFileSize(formatBytes(total));
setEdgeLocation(edge || edgeUnknown);
@ -185,7 +193,12 @@ const Logs = ({
break;
case 'result':
setLogs(data.result);
store.dispatch({ type: 'logs/load', payload: data.result.records });
store.dispatch({
type: 'logs/load', payload: {
fileName: logFileName,
logs: data.result.records,
},
});
break;
case 'metrics':
console.info(`Log parsed in ${data.elapsed}ms`);
@ -202,11 +215,31 @@ const Logs = ({
};
} catch (error) {
setFetchError(error as Error);
throw error;
}
};
if (!loadedLogs.length) {
// user navigated to logs root page
if (!routeMatch?.params.fileName && tuneData.logFiles?.length) {
// either redirect to the first log or to the latest selected
if (loadedLogs.fileName) {
navigate(generatePath(Routes.TUNE_LOGS_FILE, { tuneId: tuneData.tuneId, fileName: loadedLogs.fileName }));
} else {
const firstLogFile = (tuneData.logFiles || [])[0];
navigate(generatePath(Routes.TUNE_LOGS_FILE, { tuneId: tuneData.tuneId, fileName: firstLogFile }));
}
return undefined;
}
// first visit, logs are not loaded yet
if (!(loadedLogs.logs || []).length && tuneData.tuneId) {
loadData();
}
// file changed, reload
if ((loadedLogs.logs || []).length && loadedLogs.fileName !== routeMatch?.params.fileName) {
setLogs(undefined);
store.dispatch({ type: 'logs/load', payload: {} });
loadData();
}
@ -224,12 +257,12 @@ const Logs = ({
window.removeEventListener('resize', calculateCanvasSize);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [calculateCanvasSize, config?.datalog, config?.outputChannels, loadedLogs, ui.sidebarCollapsed]);
}, [calculateCanvasSize, config?.datalog, config?.outputChannels, loadedLogs, ui.sidebarCollapsed, routeMatch?.params.fileName]);
return (
<>
<Sider {...(siderProps as any)} className="app-sidebar">
{!logs && !loadedLogs.length ?
{!logs && !(loadedLogs.logs || []).length ?
<Loader />
:
!ui.sidebarCollapsed &&
@ -279,7 +312,15 @@ const Logs = ({
<PerfectScrollbar options={{ suppressScrollX: true }}>
{tuneData.logFiles?.map((fileName) => (
<Typography.Paragraph key={fileName}>
{fileName}
<Link
to={generatePath(Routes.TUNE_LOGS_FILE, { tuneId: tuneData.tuneId, fileName })}
style={
routeMatch?.params.fileName === fileName ?
{} : { color: 'inherit' }
}
>
{fileName}
</Link>
</Typography.Paragraph>
))}
</PerfectScrollbar>
@ -292,10 +333,10 @@ const Logs = ({
<Layout style={{ width: '100%', textAlign: 'center', marginTop: 50 }}>
<Content>
<div ref={contentRef} style={{ width: '100%', marginRight: margin }}>
{logs || !!loadedLogs.length
{logs || !!(loadedLogs.logs || []).length
?
<LogCanvas
data={loadedLogs || (logs!.records as LogsType)}
data={loadedLogs.logs || (logs!.records as LogsType)}
width={canvasWidth}
height={canvasHeight}
selectedFields1={prepareSelectedFields(selectedFields1)}

View File

@ -8,6 +8,7 @@ export enum Routes {
TUNE_TUNE = '/t/:tuneId/tune',
TUNE_DIALOG = '/t/:tuneId/tune/:category/:dialog',
TUNE_LOGS = '/t/:tuneId/logs',
TUNE_LOGS_FILE = '/t/:tuneId/logs/:fileName',
TUNE_DIAGNOSE = '/t/:tuneId/diagnose',
UPLOAD = '/upload',

View File

@ -39,7 +39,7 @@ const initialState: AppState = {
details: {} as any,
},
tuneData: {} as any,
logs: [],
logs: {} as any,
config: {} as any,
ui: {
sidebarCollapsed: false,

View File

@ -11,7 +11,10 @@ export interface TuneState extends TuneWithDetails {}
export interface TuneDataState extends TunesRecordFull {}
export interface LogsState extends Logs {}
export interface LogsState {
fileName: string;
logs: Logs;
}
export interface UIState {
sidebarCollapsed: boolean;