feat(extension): add persistence of settings (#826)

This commit is contained in:
Nathan Bierema 2021-08-31 01:42:01 +00:00 committed by GitHub
parent ad23a3ed8b
commit a3a46cabf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 64 additions and 78 deletions

View File

@ -41,13 +41,15 @@
"@redux-devtools/utils": "^1.0.0-6",
"@types/jsan": "^3.1.2",
"jsan": "^3.1.13",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-icons": "^4.2.0",
"react-json-tree": "^0.15.0",
"react-redux": "^7.2.4",
"redux": "^4.1.1"
"redux": "^4.1.1",
"redux-persist": "^6.0.0"
},
"devDependencies": {
"@babel/register": "^7.15.3",

View File

@ -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 panelDispatcher from '../middlewares/panelSync';
import rootReducer from '../reducers/panel';
import { StoreState } from '@redux-devtools/app/lib/reducers';
import rootReducer, { StoreStateWithoutSocket } from '../reducers/panel';
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(
position: string,
bgConnection: chrome.runtime.Port,
preloadedState: PreloadedState<StoreState>
bgConnection: chrome.runtime.Port
) {
const enhancer = applyMiddleware(exportState, panelDispatcher(bgConnection));
return createStore(rootReducer, preloadedState, enhancer);
const store = createStore(persistedReducer, enhancer);
const persistor = persistStore(store);
return { store, persistor };
}

View File

@ -3,15 +3,15 @@ import {
compose,
applyMiddleware,
Store,
PreloadedState,
StoreEnhancer,
Reducer,
} from 'redux';
import localForage from 'localforage';
import { persistReducer, persistStore } from 'redux-persist';
import exportState from '@redux-devtools/app/lib/middlewares/exportState';
import api from '@redux-devtools/app/lib/middlewares/api';
import { CONNECT_REQUEST } from '@redux-devtools/app/lib/constants/socketActionTypes';
import { StoreState } from '@redux-devtools/app/lib/reducers';
import {
StoreAction,
StoreActionWithoutUpdateState,
UpdateStateAction,
} from '@redux-devtools/app/lib/actions';
@ -22,6 +22,7 @@ import rootReducer from '../reducers/window';
import { BackgroundState } from '../reducers/background';
import { BackgroundAction } from './backgroundStore';
import { EmptyUpdateStateAction, NAAction } from '../middlewares/api';
import { StoreState } from '@redux-devtools/app/lib/reducers';
export interface ExpandedUpdateStateAction extends UpdateStateAction {
readonly instances: InstancesState;
@ -33,10 +34,20 @@ export type WindowStoreAction =
| NAAction
| 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(
baseStore: Store<BackgroundState, BackgroundAction>,
position: string,
preloadedState: PreloadedState<StoreState>
position: string
) {
let enhancer: StoreEnhancer;
const middlewares = [exportState, api, syncStores(baseStore)];
@ -54,7 +65,8 @@ export default function configureStore(
: (noop: unknown) => noop
);
}
const store = createStore(rootReducer, preloadedState, enhancer);
const store = createStore(persistedReducer, enhancer);
const persistor = persistStore(store);
if (
store.getState().connection.options.hostname &&
@ -65,5 +77,5 @@ export default function configureStore(
});
}
return store;
return { store, persistor };
}

View File

@ -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);
}
);
}

View File

@ -1,17 +1,17 @@
import React, { CSSProperties } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Provider } from 'react-redux';
import { Persistor } from 'redux-persist';
import { REMOVE_INSTANCE } from '@redux-devtools/app/lib/constants/actionTypes';
import App from '../../../app/containers/App';
import configureStore from '../../../app/stores/panelStore';
import getPreloadedState from '../background/getPreloadedState';
import '../../views/devpanel.pug';
import { Action, PreloadedState, Store } from 'redux';
import { StoreState } from '@redux-devtools/app/lib/reducers';
import { Action, Store } from 'redux';
import { StoreAction } from '@redux-devtools/app/lib/actions';
import { PanelMessage } from '../../../app/middlewares/api';
import { StoreStateWithoutSocket } from '../../../app/reducers/panel';
import { PersistGate } from 'redux-persist/integration/react';
const position = location.hash;
const messageStyle: CSSProperties = {
@ -22,24 +22,22 @@ const messageStyle: CSSProperties = {
let rendered: boolean | undefined;
let store: Store<StoreStateWithoutSocket, StoreAction> | undefined;
let persistor: Persistor | undefined;
let bgConnection: chrome.runtime.Port;
let naTimeout: NodeJS.Timeout;
let preloadedState: PreloadedState<StoreState>;
const isChrome = navigator.userAgent.indexOf('Firefox') === -1;
getPreloadedState(position, (state) => {
preloadedState = state;
});
function renderDevTools() {
const node = document.getElementById('root');
unmountComponentAtNode(node!);
clearTimeout(naTimeout);
store = configureStore(position, bgConnection, preloadedState);
({ store, persistor } = configureStore(position, bgConnection));
render(
<Provider store={store}>
<App position={position} />
<PersistGate loading={null} persistor={persistor}>
<App position={position} />
</PersistGate>
</Provider>,
node
);

View File

@ -1,25 +1,19 @@
import React from 'react';
import { render } from 'react-dom';
import { PreloadedState } from 'redux';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
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 configureStore from '../../../app/stores/windowStore';
import getPreloadedState from '../background/getPreloadedState';
import { MonitorMessage } from '../../../app/middlewares/api';
import '../../views/window.pug';
const position = location.hash;
let preloadedState: PreloadedState<StoreState>;
getPreloadedState(position, (state) => {
preloadedState = state;
});
chrome.runtime.getBackgroundPage((window) => {
const { store } = window!;
const localStore = configureStore(store, position, preloadedState);
const { store: localStore, persistor } = configureStore(store, position);
let name = 'monitor';
if (chrome && chrome.devtools && chrome.devtools.inspectedWindow) {
name += chrome.devtools.inspectedWindow.tabId;
@ -33,7 +27,9 @@ chrome.runtime.getBackgroundPage((window) => {
render(
<Provider store={localStore}>
<App position={position} />
<PersistGate loading={null} persistor={persistor}>
<App position={position} />
</PersistGate>
</Provider>,
document.getElementById('root')
);

View File

@ -4,7 +4,7 @@ import { Provider } from 'react-redux';
import configureStore from '../../../src/app/stores/windowStore';
import App from '../../../src/app/containers/App';
const store = configureStore(store);
const { store } = configureStore(store);
const component = mount(
<Provider store={store}>
<App position="devtools-left" />

View File

@ -43,6 +43,7 @@ describe('Chrome extension', function () {
});
it("should contain inspector monitor's component", async () => {
await delay(500);
const val = await driver
.findElement(webdriver.By.xpath('//div[contains(@class, "inspector-")]'))
.getText();

View File

@ -1,4 +1,4 @@
import { createStore, compose, applyMiddleware } from 'redux';
import { createStore, compose, applyMiddleware, Reducer } from 'redux';
import localForage from 'localforage';
import { persistReducer, persistStore } from 'redux-persist';
import api from '../middlewares/api';
@ -12,7 +12,10 @@ const persistConfig = {
storage: localForage,
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
const persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(
persistConfig,
rootReducer
) as any;
export default function configureStore() {
let composeEnhancers = compose;
@ -40,8 +43,8 @@ export default function configureStore() {
}
}
const store = createStore<StoreState, StoreAction, unknown, unknown>(
persistedReducer as any,
const store = createStore(
persistedReducer,
composeEnhancers(applyMiddleware(exportState, api))
);
const persistor = persistStore(store);

View File

@ -25958,6 +25958,7 @@ fsevents@^1.2.7:
eslint-plugin-react-hooks: ^4.2.0
gitbook-cli: ^2.3.2
jsan: ^3.1.13
localforage: ^1.10.0
lodash: ^4.17.21
path-browserify: ^1.0.1
react: ^16.14.0
@ -25968,6 +25969,7 @@ fsevents@^1.2.7:
react-transform-catch-errors: ^1.0.2
react-transform-hmr: ^1.0.4
redux: ^4.1.1
redux-persist: ^6.0.0
selenium-webdriver: ^3.6.0
sinon-chrome: ^3.0.1
languageName: unknown