mirror of
https://github.com/hibiken/asynqmon.git
synced 2025-01-19 03:05:53 +08:00
Persist slice of redux state in local storage
This commit is contained in:
parent
b1398742b9
commit
1df5004203
@ -26,7 +26,7 @@ import DoubleArrowIcon from "@material-ui/icons/DoubleArrow";
|
|||||||
import CloseIcon from "@material-ui/icons/Close";
|
import CloseIcon from "@material-ui/icons/Close";
|
||||||
import { AppState } from "./store";
|
import { AppState } from "./store";
|
||||||
import { paths } from "./paths";
|
import { paths } from "./paths";
|
||||||
import { makeTheme } from "./theme";
|
import { useTheme } from "./theme";
|
||||||
import { closeSnackbar } from "./actions/snackbarActions";
|
import { closeSnackbar } from "./actions/snackbarActions";
|
||||||
import ListItemLink from "./components/ListItemLink";
|
import ListItemLink from "./components/ListItemLink";
|
||||||
import SchedulersView from "./views/SchedulersView";
|
import SchedulersView from "./views/SchedulersView";
|
||||||
@ -146,7 +146,7 @@ function SlideUpTransition(props: TransitionProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function App(props: ConnectedProps<typeof connector>) {
|
function App(props: ConnectedProps<typeof connector>) {
|
||||||
const theme = makeTheme(props.themePreference);
|
const theme = useTheme(props.themePreference);
|
||||||
const classes = useStyles(theme)();
|
const classes = useStyles(theme)();
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const toggleDrawer = () => setOpen(!open);
|
const toggleDrawer = () => setOpen(!open);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ThemePreference } from "../reducers/settingsReducer";
|
import { ThemePreference } from "../reducers/settingsReducer";
|
||||||
|
|
||||||
// List of settings related action types.
|
// List of settings related action types.
|
||||||
export const POLL_INTERVAL_CHANGE = "POLL_INTERVAL_CHANGE";
|
export const POLL_INTERVAL_CHANGE = "POLL_INTERVAL_CHANGE";
|
||||||
export const THEME_PREFERENCE_CHANGE = "THEME_PREFERENCE_CHANGE";
|
export const THEME_PREFERENCE_CHANGE = "THEME_PREFERENCE_CHANGE";
|
||||||
|
@ -5,6 +5,11 @@ import { Provider } from "react-redux";
|
|||||||
import App from "./App";
|
import App from "./App";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
import * as serviceWorker from "./serviceWorker";
|
import * as serviceWorker from "./serviceWorker";
|
||||||
|
import { saveState } from "./localStorage";
|
||||||
|
|
||||||
|
store.subscribe(() => {
|
||||||
|
saveState(store.getState());
|
||||||
|
});
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
24
ui/src/localStorage.ts
Normal file
24
ui/src/localStorage.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { AppState } from "./store";
|
||||||
|
|
||||||
|
const LOCAL_STORAGE_KEY = "asynqmon:state";
|
||||||
|
|
||||||
|
export function loadState(): AppState | undefined {
|
||||||
|
try {
|
||||||
|
const serializedState = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||||
|
if (serializedState === null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return JSON.parse(serializedState);
|
||||||
|
} catch (err) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveState(state: AppState) {
|
||||||
|
try {
|
||||||
|
const serializedState = JSON.stringify({ settings: state.settings });
|
||||||
|
localStorage.setItem(LOCAL_STORAGE_KEY, serializedState);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("saveState: could not save state: ", err);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import schedulerEntriesReducer from "./reducers/schedulerEntriesReducer";
|
|||||||
import snackbarReducer from "./reducers/snackbarReducer";
|
import snackbarReducer from "./reducers/snackbarReducer";
|
||||||
import queueStatsReducer from "./reducers/queueStatsReducer";
|
import queueStatsReducer from "./reducers/queueStatsReducer";
|
||||||
import redisInfoReducer from "./reducers/redisInfoReducer";
|
import redisInfoReducer from "./reducers/redisInfoReducer";
|
||||||
|
import { loadState } from "./localStorage";
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
settings: settingsReducer,
|
settings: settingsReducer,
|
||||||
@ -19,9 +20,14 @@ const rootReducer = combineReducers({
|
|||||||
redis: redisInfoReducer,
|
redis: redisInfoReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const preloadedState = loadState();
|
||||||
|
|
||||||
// AppState is the top-level application state maintained by redux store.
|
// AppState is the top-level application state maintained by redux store.
|
||||||
export type AppState = ReturnType<typeof rootReducer>;
|
export type AppState = ReturnType<typeof rootReducer>;
|
||||||
|
|
||||||
export default configureStore({
|
const store = configureStore({
|
||||||
reducer: rootReducer,
|
reducer: rootReducer,
|
||||||
|
preloadedState,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export default store;
|
||||||
|
@ -2,8 +2,7 @@ import { createMuiTheme, Theme } from "@material-ui/core/styles";
|
|||||||
import { ThemePreference } from "./reducers/settingsReducer";
|
import { ThemePreference } from "./reducers/settingsReducer";
|
||||||
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
||||||
|
|
||||||
export function makeTheme(themePreference: ThemePreference): Theme {
|
export function useTheme(themePreference: ThemePreference): Theme {
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
let prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
let prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||||
if (themePreference === ThemePreference.Always) {
|
if (themePreference === ThemePreference.Always) {
|
||||||
prefersDarkMode = true;
|
prefersDarkMode = true;
|
||||||
|
@ -63,14 +63,14 @@ function SettingsView(props: PropsFromRedux) {
|
|||||||
props.selectTheme(event.target.value as ThemePreference);
|
props.selectTheme(event.target.value as ThemePreference);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg" className={classes.container}>
|
<Container maxWidth="md" className={classes.container}>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Typography variant="h5" color="textPrimary">
|
<Typography variant="h5" color="textPrimary">
|
||||||
Settings
|
Settings
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={5}>
|
<Grid item xs={6}>
|
||||||
<Paper className={classes.paper} variant="outlined">
|
<Paper className={classes.paper} variant="outlined">
|
||||||
<Typography color="textPrimary">Polling Interval</Typography>
|
<Typography color="textPrimary">Polling Interval</Typography>
|
||||||
<Typography gutterBottom color="textSecondary" variant="subtitle1">
|
<Typography gutterBottom color="textSecondary" variant="subtitle1">
|
||||||
@ -93,22 +93,26 @@ function SettingsView(props: PropsFromRedux) {
|
|||||||
/>
|
/>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Grid>
|
</Grid>
|
||||||
<FormControl variant="outlined" className={classes.formControl}>
|
<Grid item>
|
||||||
<InputLabel id="theme-label">Dark theme</InputLabel>
|
<Paper className={classes.paper} variant="outlined">
|
||||||
<Select
|
<FormControl variant="outlined" className={classes.formControl}>
|
||||||
labelId="theme-label"
|
<InputLabel id="theme-label">Dark theme</InputLabel>
|
||||||
id="theme-selected"
|
<Select
|
||||||
value={props.themePreference}
|
labelId="theme-label"
|
||||||
onChange={handleThemeChange}
|
id="theme-selected"
|
||||||
label="theme preference"
|
value={props.themePreference}
|
||||||
>
|
onChange={handleThemeChange}
|
||||||
<MenuItem value={ThemePreference.SystemDefault}>
|
label="theme preference"
|
||||||
System Default
|
>
|
||||||
</MenuItem>
|
<MenuItem value={ThemePreference.SystemDefault}>
|
||||||
<MenuItem value={ThemePreference.Always}>Always</MenuItem>
|
System Default
|
||||||
<MenuItem value={ThemePreference.Never}>Never</MenuItem>
|
</MenuItem>
|
||||||
</Select>
|
<MenuItem value={ThemePreference.Always}>Always</MenuItem>
|
||||||
</FormControl>
|
<MenuItem value={ThemePreference.Never}>Never</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</Paper>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user