mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-22 09:36:43 +03:00
feat(extension): add persistence of settings (#826)
This commit is contained in:
parent
ad23a3ed8b
commit
a3a46cabf0
|
@ -41,13 +41,15 @@
|
||||||
"@redux-devtools/utils": "^1.0.0-6",
|
"@redux-devtools/utils": "^1.0.0-6",
|
||||||
"@types/jsan": "^3.1.2",
|
"@types/jsan": "^3.1.2",
|
||||||
"jsan": "^3.1.13",
|
"jsan": "^3.1.13",
|
||||||
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
"react-icons": "^4.2.0",
|
"react-icons": "^4.2.0",
|
||||||
"react-json-tree": "^0.15.0",
|
"react-json-tree": "^0.15.0",
|
||||||
"react-redux": "^7.2.4",
|
"react-redux": "^7.2.4",
|
||||||
"redux": "^4.1.1"
|
"redux": "^4.1.1",
|
||||||
|
"redux-persist": "^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/register": "^7.15.3",
|
"@babel/register": "^7.15.3",
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
import { createStore, applyMiddleware, PreloadedState } from 'redux';
|
import { createStore, applyMiddleware, PreloadedState, Reducer } from 'redux';
|
||||||
|
import localForage from 'localforage';
|
||||||
|
import { persistReducer, persistStore } from 'redux-persist';
|
||||||
import exportState from '@redux-devtools/app/lib/middlewares/exportState';
|
import exportState from '@redux-devtools/app/lib/middlewares/exportState';
|
||||||
import panelDispatcher from '../middlewares/panelSync';
|
import panelDispatcher from '../middlewares/panelSync';
|
||||||
import rootReducer from '../reducers/panel';
|
import rootReducer, { StoreStateWithoutSocket } from '../reducers/panel';
|
||||||
import { StoreState } from '@redux-devtools/app/lib/reducers';
|
import { StoreAction } from '@redux-devtools/app/lib/actions';
|
||||||
|
|
||||||
|
const persistConfig = {
|
||||||
|
key: 'redux-devtools',
|
||||||
|
blacklist: ['instances', 'socket'],
|
||||||
|
storage: localForage,
|
||||||
|
};
|
||||||
|
|
||||||
|
const persistedReducer: Reducer<StoreStateWithoutSocket, StoreAction> =
|
||||||
|
persistReducer(persistConfig, rootReducer) as any;
|
||||||
|
|
||||||
export default function configureStore(
|
export default function configureStore(
|
||||||
position: string,
|
position: string,
|
||||||
bgConnection: chrome.runtime.Port,
|
bgConnection: chrome.runtime.Port
|
||||||
preloadedState: PreloadedState<StoreState>
|
|
||||||
) {
|
) {
|
||||||
const enhancer = applyMiddleware(exportState, panelDispatcher(bgConnection));
|
const enhancer = applyMiddleware(exportState, panelDispatcher(bgConnection));
|
||||||
return createStore(rootReducer, preloadedState, enhancer);
|
const store = createStore(persistedReducer, enhancer);
|
||||||
|
const persistor = persistStore(store);
|
||||||
|
return { store, persistor };
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,15 @@ import {
|
||||||
compose,
|
compose,
|
||||||
applyMiddleware,
|
applyMiddleware,
|
||||||
Store,
|
Store,
|
||||||
PreloadedState,
|
|
||||||
StoreEnhancer,
|
StoreEnhancer,
|
||||||
|
Reducer,
|
||||||
} from 'redux';
|
} from 'redux';
|
||||||
|
import localForage from 'localforage';
|
||||||
|
import { persistReducer, persistStore } from 'redux-persist';
|
||||||
import exportState from '@redux-devtools/app/lib/middlewares/exportState';
|
import exportState from '@redux-devtools/app/lib/middlewares/exportState';
|
||||||
import api from '@redux-devtools/app/lib/middlewares/api';
|
import api from '@redux-devtools/app/lib/middlewares/api';
|
||||||
import { CONNECT_REQUEST } from '@redux-devtools/app/lib/constants/socketActionTypes';
|
import { CONNECT_REQUEST } from '@redux-devtools/app/lib/constants/socketActionTypes';
|
||||||
import { StoreState } from '@redux-devtools/app/lib/reducers';
|
|
||||||
import {
|
import {
|
||||||
StoreAction,
|
|
||||||
StoreActionWithoutUpdateState,
|
StoreActionWithoutUpdateState,
|
||||||
UpdateStateAction,
|
UpdateStateAction,
|
||||||
} from '@redux-devtools/app/lib/actions';
|
} from '@redux-devtools/app/lib/actions';
|
||||||
|
@ -22,6 +22,7 @@ import rootReducer from '../reducers/window';
|
||||||
import { BackgroundState } from '../reducers/background';
|
import { BackgroundState } from '../reducers/background';
|
||||||
import { BackgroundAction } from './backgroundStore';
|
import { BackgroundAction } from './backgroundStore';
|
||||||
import { EmptyUpdateStateAction, NAAction } from '../middlewares/api';
|
import { EmptyUpdateStateAction, NAAction } from '../middlewares/api';
|
||||||
|
import { StoreState } from '@redux-devtools/app/lib/reducers';
|
||||||
|
|
||||||
export interface ExpandedUpdateStateAction extends UpdateStateAction {
|
export interface ExpandedUpdateStateAction extends UpdateStateAction {
|
||||||
readonly instances: InstancesState;
|
readonly instances: InstancesState;
|
||||||
|
@ -33,10 +34,20 @@ export type WindowStoreAction =
|
||||||
| NAAction
|
| NAAction
|
||||||
| EmptyUpdateStateAction;
|
| EmptyUpdateStateAction;
|
||||||
|
|
||||||
|
const persistConfig = {
|
||||||
|
key: 'redux-devtools',
|
||||||
|
blacklist: ['instances', 'socket'],
|
||||||
|
storage: localForage,
|
||||||
|
};
|
||||||
|
|
||||||
|
const persistedReducer: Reducer<StoreState, WindowStoreAction> = persistReducer(
|
||||||
|
persistConfig,
|
||||||
|
rootReducer
|
||||||
|
) as any;
|
||||||
|
|
||||||
export default function configureStore(
|
export default function configureStore(
|
||||||
baseStore: Store<BackgroundState, BackgroundAction>,
|
baseStore: Store<BackgroundState, BackgroundAction>,
|
||||||
position: string,
|
position: string
|
||||||
preloadedState: PreloadedState<StoreState>
|
|
||||||
) {
|
) {
|
||||||
let enhancer: StoreEnhancer;
|
let enhancer: StoreEnhancer;
|
||||||
const middlewares = [exportState, api, syncStores(baseStore)];
|
const middlewares = [exportState, api, syncStores(baseStore)];
|
||||||
|
@ -54,7 +65,8 @@ export default function configureStore(
|
||||||
: (noop: unknown) => noop
|
: (noop: unknown) => noop
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const store = createStore(rootReducer, preloadedState, enhancer);
|
const store = createStore(persistedReducer, enhancer);
|
||||||
|
const persistor = persistStore(store);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
store.getState().connection.options.hostname &&
|
store.getState().connection.options.hostname &&
|
||||||
|
@ -65,5 +77,5 @@ export default function configureStore(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return store;
|
return { store, persistor };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import { PreloadedState } from 'redux';
|
|
||||||
import { StoreState } from '@redux-devtools/app/lib/reducers';
|
|
||||||
|
|
||||||
const getIfExists = (sel: any, template: any) =>
|
|
||||||
typeof sel === 'undefined' ||
|
|
||||||
typeof template === 'undefined' ||
|
|
||||||
typeof template[sel] === 'undefined'
|
|
||||||
? 0
|
|
||||||
: sel;
|
|
||||||
|
|
||||||
export default function getPreloadedState(
|
|
||||||
position: string,
|
|
||||||
cb: (state: PreloadedState<StoreState>) => void
|
|
||||||
) {
|
|
||||||
chrome.storage.local.get(
|
|
||||||
[
|
|
||||||
'monitor' + position,
|
|
||||||
'slider' + position,
|
|
||||||
'dispatcher' + position,
|
|
||||||
'test-templates',
|
|
||||||
'test-templates-sel',
|
|
||||||
],
|
|
||||||
(options) => {
|
|
||||||
cb({
|
|
||||||
monitor: {
|
|
||||||
selected: options['monitor' + position],
|
|
||||||
sliderIsOpen: options['slider' + position] || false,
|
|
||||||
dispatcherIsOpen: options['dispatcher' + position] || false,
|
|
||||||
},
|
|
||||||
test: {
|
|
||||||
selected: getIfExists(
|
|
||||||
options['test-templates-sel'],
|
|
||||||
options['test-templates']
|
|
||||||
),
|
|
||||||
templates: options['test-templates'],
|
|
||||||
},
|
|
||||||
} as any);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,17 +1,17 @@
|
||||||
import React, { CSSProperties } from 'react';
|
import React, { CSSProperties } from 'react';
|
||||||
import { render, unmountComponentAtNode } from 'react-dom';
|
import { render, unmountComponentAtNode } from 'react-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { Persistor } from 'redux-persist';
|
||||||
import { REMOVE_INSTANCE } from '@redux-devtools/app/lib/constants/actionTypes';
|
import { REMOVE_INSTANCE } from '@redux-devtools/app/lib/constants/actionTypes';
|
||||||
import App from '../../../app/containers/App';
|
import App from '../../../app/containers/App';
|
||||||
import configureStore from '../../../app/stores/panelStore';
|
import configureStore from '../../../app/stores/panelStore';
|
||||||
import getPreloadedState from '../background/getPreloadedState';
|
|
||||||
|
|
||||||
import '../../views/devpanel.pug';
|
import '../../views/devpanel.pug';
|
||||||
import { Action, PreloadedState, Store } from 'redux';
|
import { Action, Store } from 'redux';
|
||||||
import { StoreState } from '@redux-devtools/app/lib/reducers';
|
|
||||||
import { StoreAction } from '@redux-devtools/app/lib/actions';
|
import { StoreAction } from '@redux-devtools/app/lib/actions';
|
||||||
import { PanelMessage } from '../../../app/middlewares/api';
|
import { PanelMessage } from '../../../app/middlewares/api';
|
||||||
import { StoreStateWithoutSocket } from '../../../app/reducers/panel';
|
import { StoreStateWithoutSocket } from '../../../app/reducers/panel';
|
||||||
|
import { PersistGate } from 'redux-persist/integration/react';
|
||||||
|
|
||||||
const position = location.hash;
|
const position = location.hash;
|
||||||
const messageStyle: CSSProperties = {
|
const messageStyle: CSSProperties = {
|
||||||
|
@ -22,24 +22,22 @@ const messageStyle: CSSProperties = {
|
||||||
|
|
||||||
let rendered: boolean | undefined;
|
let rendered: boolean | undefined;
|
||||||
let store: Store<StoreStateWithoutSocket, StoreAction> | undefined;
|
let store: Store<StoreStateWithoutSocket, StoreAction> | undefined;
|
||||||
|
let persistor: Persistor | undefined;
|
||||||
let bgConnection: chrome.runtime.Port;
|
let bgConnection: chrome.runtime.Port;
|
||||||
let naTimeout: NodeJS.Timeout;
|
let naTimeout: NodeJS.Timeout;
|
||||||
let preloadedState: PreloadedState<StoreState>;
|
|
||||||
|
|
||||||
const isChrome = navigator.userAgent.indexOf('Firefox') === -1;
|
const isChrome = navigator.userAgent.indexOf('Firefox') === -1;
|
||||||
|
|
||||||
getPreloadedState(position, (state) => {
|
|
||||||
preloadedState = state;
|
|
||||||
});
|
|
||||||
|
|
||||||
function renderDevTools() {
|
function renderDevTools() {
|
||||||
const node = document.getElementById('root');
|
const node = document.getElementById('root');
|
||||||
unmountComponentAtNode(node!);
|
unmountComponentAtNode(node!);
|
||||||
clearTimeout(naTimeout);
|
clearTimeout(naTimeout);
|
||||||
store = configureStore(position, bgConnection, preloadedState);
|
({ store, persistor } = configureStore(position, bgConnection));
|
||||||
render(
|
render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App position={position} />
|
<PersistGate loading={null} persistor={persistor}>
|
||||||
|
<App position={position} />
|
||||||
|
</PersistGate>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
node
|
node
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import { PreloadedState } from 'redux';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { PersistGate } from 'redux-persist/integration/react';
|
||||||
import { UPDATE_STATE } from '@redux-devtools/app/lib/constants/actionTypes';
|
import { UPDATE_STATE } from '@redux-devtools/app/lib/constants/actionTypes';
|
||||||
import { StoreState } from '@redux-devtools/app/lib/reducers';
|
|
||||||
import App from '../../../app/containers/App';
|
import App from '../../../app/containers/App';
|
||||||
import configureStore from '../../../app/stores/windowStore';
|
import configureStore from '../../../app/stores/windowStore';
|
||||||
import getPreloadedState from '../background/getPreloadedState';
|
|
||||||
import { MonitorMessage } from '../../../app/middlewares/api';
|
import { MonitorMessage } from '../../../app/middlewares/api';
|
||||||
|
|
||||||
import '../../views/window.pug';
|
import '../../views/window.pug';
|
||||||
|
|
||||||
const position = location.hash;
|
const position = location.hash;
|
||||||
let preloadedState: PreloadedState<StoreState>;
|
|
||||||
getPreloadedState(position, (state) => {
|
|
||||||
preloadedState = state;
|
|
||||||
});
|
|
||||||
|
|
||||||
chrome.runtime.getBackgroundPage((window) => {
|
chrome.runtime.getBackgroundPage((window) => {
|
||||||
const { store } = window!;
|
const { store } = window!;
|
||||||
const localStore = configureStore(store, position, preloadedState);
|
const { store: localStore, persistor } = configureStore(store, position);
|
||||||
let name = 'monitor';
|
let name = 'monitor';
|
||||||
if (chrome && chrome.devtools && chrome.devtools.inspectedWindow) {
|
if (chrome && chrome.devtools && chrome.devtools.inspectedWindow) {
|
||||||
name += chrome.devtools.inspectedWindow.tabId;
|
name += chrome.devtools.inspectedWindow.tabId;
|
||||||
|
@ -33,7 +27,9 @@ chrome.runtime.getBackgroundPage((window) => {
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<Provider store={localStore}>
|
<Provider store={localStore}>
|
||||||
<App position={position} />
|
<PersistGate loading={null} persistor={persistor}>
|
||||||
|
<App position={position} />
|
||||||
|
</PersistGate>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Provider } from 'react-redux';
|
||||||
import configureStore from '../../../src/app/stores/windowStore';
|
import configureStore from '../../../src/app/stores/windowStore';
|
||||||
import App from '../../../src/app/containers/App';
|
import App from '../../../src/app/containers/App';
|
||||||
|
|
||||||
const store = configureStore(store);
|
const { store } = configureStore(store);
|
||||||
const component = mount(
|
const component = mount(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App position="devtools-left" />
|
<App position="devtools-left" />
|
||||||
|
|
|
@ -43,6 +43,7 @@ describe('Chrome extension', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should contain inspector monitor's component", async () => {
|
it("should contain inspector monitor's component", async () => {
|
||||||
|
await delay(500);
|
||||||
const val = await driver
|
const val = await driver
|
||||||
.findElement(webdriver.By.xpath('//div[contains(@class, "inspector-")]'))
|
.findElement(webdriver.By.xpath('//div[contains(@class, "inspector-")]'))
|
||||||
.getText();
|
.getText();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createStore, compose, applyMiddleware } from 'redux';
|
import { createStore, compose, applyMiddleware, Reducer } from 'redux';
|
||||||
import localForage from 'localforage';
|
import localForage from 'localforage';
|
||||||
import { persistReducer, persistStore } from 'redux-persist';
|
import { persistReducer, persistStore } from 'redux-persist';
|
||||||
import api from '../middlewares/api';
|
import api from '../middlewares/api';
|
||||||
|
@ -12,7 +12,10 @@ const persistConfig = {
|
||||||
storage: localForage,
|
storage: localForage,
|
||||||
};
|
};
|
||||||
|
|
||||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
const persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(
|
||||||
|
persistConfig,
|
||||||
|
rootReducer
|
||||||
|
) as any;
|
||||||
|
|
||||||
export default function configureStore() {
|
export default function configureStore() {
|
||||||
let composeEnhancers = compose;
|
let composeEnhancers = compose;
|
||||||
|
@ -40,8 +43,8 @@ export default function configureStore() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = createStore<StoreState, StoreAction, unknown, unknown>(
|
const store = createStore(
|
||||||
persistedReducer as any,
|
persistedReducer,
|
||||||
composeEnhancers(applyMiddleware(exportState, api))
|
composeEnhancers(applyMiddleware(exportState, api))
|
||||||
);
|
);
|
||||||
const persistor = persistStore(store);
|
const persistor = persistStore(store);
|
||||||
|
|
|
@ -25958,6 +25958,7 @@ fsevents@^1.2.7:
|
||||||
eslint-plugin-react-hooks: ^4.2.0
|
eslint-plugin-react-hooks: ^4.2.0
|
||||||
gitbook-cli: ^2.3.2
|
gitbook-cli: ^2.3.2
|
||||||
jsan: ^3.1.13
|
jsan: ^3.1.13
|
||||||
|
localforage: ^1.10.0
|
||||||
lodash: ^4.17.21
|
lodash: ^4.17.21
|
||||||
path-browserify: ^1.0.1
|
path-browserify: ^1.0.1
|
||||||
react: ^16.14.0
|
react: ^16.14.0
|
||||||
|
@ -25968,6 +25969,7 @@ fsevents@^1.2.7:
|
||||||
react-transform-catch-errors: ^1.0.2
|
react-transform-catch-errors: ^1.0.2
|
||||||
react-transform-hmr: ^1.0.4
|
react-transform-hmr: ^1.0.4
|
||||||
redux: ^4.1.1
|
redux: ^4.1.1
|
||||||
|
redux-persist: ^6.0.0
|
||||||
selenium-webdriver: ^3.6.0
|
selenium-webdriver: ^3.6.0
|
||||||
sinon-chrome: ^3.0.1
|
sinon-chrome: ^3.0.1
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
|
Loading…
Reference in New Issue
Block a user