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

feat: remember selected runs between pages (close #774) (#788)

上级 211b2b59
import {GlobalDispatchContext, GlobalStateContext, globalState} from '~/hooks/useGlobalState';
import React, {useReducer} from 'react';
import type {FunctionComponent} from 'react';
import type {GlobalState as GlobalStateType} from '~/hooks/useGlobalState';
interface GlobalDispatch {
(state: GlobalStateType, newState: Partial<GlobalStateType>): GlobalStateType;
}
const GlobalState: FunctionComponent = ({children}) => {
const [state, dispatch] = useReducer<GlobalDispatch>((state, newState) => ({...state, ...newState}), globalState);
return (
<GlobalStateContext.Provider value={state}>
<GlobalDispatchContext.Provider value={dispatch}>{children}</GlobalDispatchContext.Provider>
</GlobalStateContext.Provider>
);
};
export default GlobalState;
import {createContext, useContext} from 'react';
import type {Dispatch} from 'react';
export interface GlobalState {
runs: string[];
}
export const globalState: GlobalState = {
runs: []
};
export const GlobalStateContext = createContext<GlobalState>(globalState);
export const GlobalDispatchContext = createContext<Dispatch<Partial<GlobalState>>>(() => void 0);
const useGlobalState = () => [useContext(GlobalStateContext), useContext(GlobalDispatchContext)] as const;
export default useGlobalState;
......@@ -6,6 +6,7 @@ import groupBy from 'lodash/groupBy';
import intersectionBy from 'lodash/intersectionBy';
import queryString from 'query-string';
import uniq from 'lodash/uniq';
import useGlobalState from '~/hooks/useGlobalState';
import {useLocation} from 'react-router-dom';
import {useRunningRequest} from '~/hooks/useRequest';
......@@ -13,6 +14,7 @@ type Tags = Record<string, string[]>;
type State = {
initRuns: string[];
globalRuns: string[];
runs: Run[];
selectedRuns: Run[];
initTags: Tags;
......@@ -86,12 +88,16 @@ const reducer = (state: State, action: Action): State => {
switch (action.type) {
case ActionType.initRuns:
const initRuns = action.payload;
const initRunsGlobalRuns = state.globalRuns.length ? state.globalRuns : initRuns;
const initRunsRuns = attachRunColor(initRuns);
const initRunsSelectedRuns = state.selectedRuns.filter(run => initRuns.includes(run.label));
const initRunsSelectedRuns = state.globalRuns.length
? initRunsRuns.filter(run => initRunsGlobalRuns.includes(run.label))
: initRunsRuns;
const initRunsTags = groupTags(initRunsSelectedRuns, state.initTags);
return {
...state,
initRuns,
globalRuns: initRunsGlobalRuns,
runs: initRunsRuns,
selectedRuns: initRunsSelectedRuns,
tags: initRunsTags,
......@@ -111,6 +117,7 @@ const reducer = (state: State, action: Action): State => {
const setSelectedRunsTags = groupTags(action.payload, state.initTags);
return {
...state,
globalRuns: action.payload.map(run => run.label),
selectedRuns: action.payload,
tags: setSelectedRunsTags,
selectedTags: setSelectedRunsTags
......@@ -146,6 +153,8 @@ const useTagFilter = (type: string, running: boolean) => {
const {data, loading, error} = useRunningRequest<TagsData>(`/${type}/tags`, running);
const [globalState, globalDispatch] = useGlobalState();
const runs: string[] = useMemo(() => data?.runs ?? [], [data]);
const tags: Tags = useMemo(
() =>
......@@ -164,6 +173,7 @@ const useTagFilter = (type: string, running: boolean) => {
const [state, dispatch] = useReducer(reducer, {
initRuns: [],
globalRuns: globalState.runs,
runs: [],
selectedRuns: [],
initTags: {},
......@@ -176,18 +186,23 @@ const useTagFilter = (type: string, running: boolean) => {
[query]
);
const runsFromQuery = useMemo(
() => (queryRuns.length ? state.runs.filter(run => queryRuns.includes(run.label)) : state.runs),
[state.runs, queryRuns]
);
const onChangeRuns = useCallback((runs: Run[]) => dispatch({type: ActionType.setSelectedRuns, payload: runs}), []);
const onChangeTags = useCallback((tags: Tag[]) => dispatch({type: ActionType.setSelectedTags, payload: tags}), []);
useEffect(() => dispatch({type: ActionType.initRuns, payload: runs || []}), [runs]);
useEffect(() => dispatch({type: ActionType.setSelectedRuns, payload: runsFromQuery}), [runsFromQuery]);
useEffect(() => dispatch({type: ActionType.initTags, payload: tags || {}}), [tags]);
useEffect(() => {
if (queryRuns.length) {
const runs = state.runs.filter(run => queryRuns.includes(run.label));
dispatch({
type: ActionType.setSelectedRuns,
payload: runs.length ? runs : state.runs
});
}
}, [queryRuns, state.runs]);
useEffect(() => globalDispatch({runs: state.globalRuns}), [state.globalRuns, globalDispatch]);
const tagsWithSingleRun = useMemo(
() =>
state.tags.reduce<TagWithSingleRun[]>((prev, {runs, ...item}) => {
......
......@@ -2,6 +2,7 @@ import '~/utils/i18n';
import App from './App';
import BodyLoading from '~/components/BodyLoading';
import GlobalState from '~/components/GlobalState';
import {GlobalStyle} from '~/utils/style';
import React from 'react';
import ReactDOM from 'react-dom';
......@@ -22,7 +23,9 @@ ReactDOM.render(
<React.StrictMode>
<GlobalStyle />
<React.Suspense fallback={<BodyLoading />}>
<App />
<GlobalState>
<App />
</GlobalState>
</React.Suspense>
</React.StrictMode>,
document.getElementById('root')
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册