未验证 提交 b7726fde 编写于 作者: P Peter Pan 提交者: GitHub

fix bugs from Kristy and improve interaction (#809)

* feat: split page runs in global states

* fix: bring loading back when switching to a visited page

* fix: scroll tooltips in scalar & pr-curve to prevent content overflow
上级 507627e1
......@@ -8,8 +8,24 @@ interface GlobalDispatch {
(state: GlobalStateType, newState: Partial<GlobalStateType>): GlobalStateType;
}
// TODO: use redux
const GlobalState: FunctionComponent = ({children}) => {
const [state, dispatch] = useReducer<GlobalDispatch>((state, newState) => ({...state, ...newState}), globalState);
const [state, dispatch] = useReducer<GlobalDispatch>(
(state, newState) =>
Object.entries(newState).reduce(
(m, [key, value]) => {
if (m.hasOwnProperty(key)) {
m[key] = {...m[key], ...value};
} else {
m[key] = value;
}
return m;
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
{...state} as any
),
globalState
);
return (
<GlobalStateContext.Provider value={state}>
......
......@@ -171,7 +171,9 @@ const PRCurveChart: FunctionComponent<PRCurveChartProps> = ({cid, runs, tag, run
...chartOptions,
tooltip: {
...chartOptions.tooltip,
formatter
formatter,
hideDelay: 300,
enterable: true
}
}),
[formatter]
......
......@@ -204,7 +204,9 @@ const ScalarChart: FunctionComponent<ScalarChartProps> = ({
...chartOptions,
tooltip: {
...chartOptions.tooltip,
formatter
formatter,
hideDelay: 300,
enterable: true
},
xAxis: {
type: xAxisType,
......
......@@ -5,6 +5,10 @@ import type {Run} from '~/types';
import styled from 'styled-components';
const Wrapper = styled.div`
max-height: ${rem(160)};
overflow: hidden auto;
overscroll-behavior: auto contain;
table {
border-spacing: none;
text-align: left;
......
......@@ -30,6 +30,8 @@ const useECharts = <T extends HTMLElement, W extends HTMLElement = HTMLDivElemen
const onInit = useRef(options.onInit);
const onDispose = useRef(options.onDispose);
const hideTip = useCallback(() => echartInstance.current?.dispatchAction({type: 'hideTip'}), []);
const createChart = useCallback(() => {
(async () => {
const {default: echarts} = await import('echarts');
......@@ -41,6 +43,8 @@ const useECharts = <T extends HTMLElement, W extends HTMLElement = HTMLDivElemen
}
echartInstance.current = echarts.init((ref.current as unknown) as HTMLDivElement);
ref.current.addEventListener('mouseleave', hideTip);
setTimeout(() => {
if (options.zoom) {
echartInstance.current?.dispatchAction({
......@@ -57,15 +61,16 @@ const useECharts = <T extends HTMLElement, W extends HTMLElement = HTMLDivElemen
setEchart(echartInstance.current);
})();
}, [options.gl, options.zoom]);
}, [options.gl, options.zoom, hideTip]);
const destroyChart = useCallback(() => {
if (echartInstance.current) {
onDispose.current?.(echartInstance.current);
}
echartInstance.current?.dispose();
ref.current?.removeEventListener('mouseleave', hideTip);
setEchart(null);
}, []);
}, [hideTip]);
useEffect(() => {
createChart();
......
......@@ -3,13 +3,45 @@ import {createContext, useContext} from 'react';
import type {Dispatch} from 'react';
export interface GlobalState {
runs: string[];
model: FileList | File[] | null;
scalar: {
runs: string[];
};
histogram: {
runs: string[];
};
image: {
runs: string[];
};
audio: {
runs: string[];
};
prCurve: {
runs: string[];
};
graph: {
model: FileList | File[] | null;
};
}
export const globalState: GlobalState = {
runs: [],
model: null
scalar: {
runs: []
},
histogram: {
runs: []
},
image: {
runs: []
},
audio: {
runs: []
},
prCurve: {
runs: []
},
graph: {
model: null
}
};
export const GlobalStateContext = createContext<GlobalState>(globalState);
......
......@@ -2,6 +2,8 @@ import type {Run, Tag, TagWithSingleRun, TagsData} from '~/types';
import {color, colorAlt} from '~/utils/chart';
import {useCallback, useEffect, useMemo, useReducer} from 'react';
import {cache} from 'swr';
import camelCase from 'lodash/camelCase';
import groupBy from 'lodash/groupBy';
import intersection from 'lodash/intersection';
import intersectionBy from 'lodash/intersectionBy';
......@@ -163,7 +165,16 @@ const useTagFilter = (type: string, running: boolean) => {
const {data, loading, error} = useRunningRequest<TagsData>(`/${type}/tags`, running);
// clear cache in order to fully reload data when switching page
useEffect(() => () => cache.delete(`/${type}/tags`), [type]);
const pageName = useMemo(() => camelCase(type), [type]);
const [globalState, globalDispatch] = useGlobalState();
const storedRuns = useMemo(
() => ((globalState as unknown) as Record<string, {runs: string[]}>)[camelCase(pageName)]?.runs ?? [],
[pageName, globalState]
);
const runs: string[] = useMemo(() => data?.runs ?? [], [data]);
const tags: Tags = useMemo(
......@@ -183,7 +194,7 @@ const useTagFilter = (type: string, running: boolean) => {
const [state, dispatch] = useReducer(reducer, {
initRuns: [],
globalRuns: globalState.runs,
globalRuns: storedRuns,
runs: [],
selectedRuns: [],
initTags: {},
......@@ -211,7 +222,15 @@ const useTagFilter = (type: string, running: boolean) => {
});
}
}, [queryRuns, state.runs]);
useEffect(() => globalDispatch({runs: state.globalRuns}), [state.globalRuns, globalDispatch]);
useEffect(
() =>
globalDispatch({
[pageName]: {
runs: state.globalRuns
}
}),
[pageName, state.globalRuns, globalDispatch]
);
const tagsWithSingleRun = useMemo(
() =>
......
......@@ -75,7 +75,7 @@ const Graph: FunctionComponent = () => {
const graph = useRef<GraphRef>(null);
const file = useRef<HTMLInputElement>(null);
const [files, setFiles] = useState<FileList | File[] | null>(globalState.model);
const [files, setFiles] = useState<FileList | File[] | null>(globalState.graph.model);
const onClickFile = useCallback(() => {
if (file.current) {
file.current.value = '';
......@@ -86,7 +86,7 @@ const Graph: FunctionComponent = () => {
(e: React.ChangeEvent<HTMLInputElement>) => {
const target = e.target;
if (target && target.files && target.files.length) {
globalDispatch({model: target.files});
globalDispatch({graph: {model: target.files}});
setFiles(target.files);
}
},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册