diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 8d238942..8e4943d1 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [master] + branches: [main] pull_request: - branches: [master] + branches: [main] jobs: build: diff --git a/extension/README.md b/extension/README.md index 74167cce..ba9fe3b8 100644 --- a/extension/README.md +++ b/extension/README.md @@ -100,7 +100,7 @@ To specify [extension’s options](https://github.com/zalmoxisus/redux-devtools- const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ - // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize... + // Specify extension’s options like name, actionsDenylist, actionsCreators, serialize... }) : compose; @@ -143,7 +143,7 @@ import { createStore, applyMiddleware } from 'redux'; import { composeWithDevTools } from 'redux-devtools-extension'; const composeEnhancers = composeWithDevTools({ - // Specify name here, actionsBlacklist, actionsCreators and other options if needed + // Specify name here, actionsDenylist, actionsCreators and other options if needed }); const store = createStore( reducer, @@ -165,7 +165,7 @@ import { devToolsEnhancer } from 'redux-devtools-extension'; const store = createStore( reducer, /* preloadedState, */ devToolsEnhancer() - // Specify name here, actionsBlacklist, actionsCreators and other options if needed + // Specify name here, actionsDenylist, actionsCreators and other options if needed ); ``` diff --git a/extension/docs/API/Arguments.md b/extension/docs/API/Arguments.md index fe632424..2284b110 100644 --- a/extension/docs/API/Arguments.md +++ b/extension/docs/API/Arguments.md @@ -240,9 +240,9 @@ const store = createStore( ); ``` -### `actionsBlacklist` / `actionsWhitelist` +### `actionsDenylist` / `actionsAllowlist` -_string or array of strings as regex_ - actions types to be hidden / shown in the monitors (while passed to the reducers). If `actionsWhitelist` specified, `actionsBlacklist` is ignored. +_string or array of strings as regex_ - actions types to be hidden / shown in the monitors (while passed to the reducers). If `actionsAllowlist` specified, `actionsDenylist` is ignored. Example: @@ -251,16 +251,16 @@ createStore( reducer, remotedev({ sendTo: 'http://localhost:8000', - actionsBlacklist: 'SOME_ACTION', - // or actionsBlacklist: ['SOME_ACTION', 'SOME_OTHER_ACTION'] - // or just actionsBlacklist: 'SOME_' to omit both + actionsDenylist: 'SOME_ACTION', + // or actionsDenylist: ['SOME_ACTION', 'SOME_OTHER_ACTION'] + // or just actionsDenylist: 'SOME_' to omit both }) ); ``` ### `predicate` -_function_ - called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor. Use it as a more advanced version of `actionsBlacklist`/`actionsWhitelist` parameters. +_function_ - called for every action before sending, takes `state` and `action` object, and returns `true` in case it allows sending the current data to the monitor. Use it as a more advanced version of `actionsDenylist`/`actionsAllowlist` parameters. Example of usage: ```js diff --git a/extension/docs/Recipes.md b/extension/docs/Recipes.md index 5bc8e751..ecae09e1 100644 --- a/extension/docs/Recipes.md +++ b/extension/docs/Recipes.md @@ -65,13 +65,13 @@ const store = createStore( /* preloadedState, */ compose( devToolsEnhancer({ instaceID: 1, - name: 'Blacklisted', - actionsBlacklist: '...', + name: 'Denylisted', + actionsDenylist: '...', }), devToolsEnhancer({ instaceID: 2, - name: 'Whitelisted', - actionsWhitelist: '...', + name: 'Allowlisted', + actionsAllowlist: '...', }) ) ); diff --git a/extension/src/app/api/filters.ts b/extension/src/app/api/filters.ts index 37fa4ae9..9f15b9e7 100644 --- a/extension/src/app/api/filters.ts +++ b/extension/src/app/api/filters.ts @@ -5,13 +5,13 @@ import { LiftedState, PerformAction } from '@redux-devtools/instrument'; export type FilterStateValue = | 'DO_NOT_FILTER' - | 'BLACKLIST_SPECIFIC' - | 'WHITELIST_SPECIFIC'; + | 'DENYLIST_SPECIFIC' + | 'ALLOWLIST_SPECIFIC'; export const FilterState: { [K in FilterStateValue]: FilterStateValue } = { DO_NOT_FILTER: 'DO_NOT_FILTER', - BLACKLIST_SPECIFIC: 'BLACKLIST_SPECIFIC', - WHITELIST_SPECIFIC: 'WHITELIST_SPECIFIC', + DENYLIST_SPECIFIC: 'DENYLIST_SPECIFIC', + ALLOWLIST_SPECIFIC: 'ALLOWLIST_SPECIFIC', }; function isArray(arg: unknown): arg is readonly unknown[] { @@ -19,19 +19,17 @@ function isArray(arg: unknown): arg is readonly unknown[] { } interface LocalFilter { - readonly whitelist: string | undefined; - readonly blacklist: string | undefined; + readonly allowlist: string | undefined; + readonly denylist: string | undefined; } export function getLocalFilter(config: Config): LocalFilter | undefined { - if (config.actionsBlacklist || config.actionsWhitelist) { + const denylist = config.actionsDenylist ?? config.actionsBlacklist; + const allowlist = config.actionsAllowlist ?? config.actionsWhitelist; + if (denylist || allowlist) { return { - whitelist: isArray(config.actionsWhitelist) - ? config.actionsWhitelist.join('|') - : config.actionsWhitelist, - blacklist: isArray(config.actionsBlacklist) - ? config.actionsBlacklist.join('|') - : config.actionsBlacklist, + allowlist: isArray(allowlist) ? allowlist.join('|') : allowlist, + denylist: isArray(denylist) ? denylist.join('|') : denylist, }; } return undefined; @@ -56,11 +54,11 @@ export function isFiltered>( return false; } - const { whitelist, blacklist } = localFilter || window.devToolsOptions || {}; + const { allowlist, denylist } = localFilter || window.devToolsOptions || {}; const actionType = ((action as A).type || action) as string; return ( - (whitelist && !actionType.match(whitelist)) || - (blacklist && actionType.match(blacklist)) + (allowlist && !actionType.match(allowlist)) || + (denylist && actionType.match(denylist)) ); } diff --git a/extension/src/app/middlewares/api.ts b/extension/src/app/middlewares/api.ts index ce36b002..f74b7181 100644 --- a/extension/src/app/middlewares/api.ts +++ b/extension/src/app/middlewares/api.ts @@ -3,6 +3,8 @@ import { UPDATE_STATE, REMOVE_INSTANCE, LIFTED_ACTION, + TOGGLE_PERSIST, + SET_PERSIST, } from '@redux-devtools/app/lib/constants/actionTypes'; import { nonReduxDispatch } from '@redux-devtools/app/lib/utils/monitorActions'; import syncOptions, { @@ -18,8 +20,9 @@ import { CustomAction, DispatchAction as AppDispatchAction, LibConfig, + SetPersistAction, } from '@redux-devtools/app/lib/actions'; -import { Action, Dispatch } from 'redux'; +import { Action, Dispatch, MiddlewareAPI } from 'redux'; import { ContentScriptToBackgroundMessage, SplitMessage, @@ -35,6 +38,7 @@ import { LiftedActionAction, } from '../stores/backgroundStore'; import { Position } from '../api/openWindow'; +import { BackgroundState } from '../reducers/background'; interface TabMessageBase { readonly type: string; @@ -183,8 +187,13 @@ export type TabMessage = export type PanelMessage> = | NAAction | ErrorMessage - | UpdateStateAction; -export type MonitorMessage = NAAction | ErrorMessage | EmptyUpdateStateAction; + | UpdateStateAction + | SetPersistAction; +export type MonitorMessage = + | NAAction + | ErrorMessage + | EmptyUpdateStateAction + | SetPersistAction; type TabPort = Omit & { postMessage: (message: TabMessage) => void; @@ -224,7 +233,8 @@ const getId = (sender: chrome.runtime.MessageSender, name?: string) => type MonitorAction> = | NAAction | ErrorMessage - | UpdateStateAction; + | UpdateStateAction + | SetPersistAction; function toMonitors>( action: MonitorAction, @@ -233,7 +243,9 @@ function toMonitors>( ) { Object.keys(connections.monitor).forEach((id) => { connections.monitor[id].postMessage( - verbose || action.type === 'ERROR' ? action : { type: UPDATE_STATE } + verbose || action.type === 'ERROR' || action.type === SET_PERSIST + ? action + : { type: UPDATE_STATE } ); }); Object.keys(connections.panel).forEach((id) => { @@ -582,9 +594,18 @@ declare global { window.syncOptions = syncOptions(toAllTabs); // Expose to the options page -export default function api() { +export default function api( + store: MiddlewareAPI, BackgroundState> +) { return (next: Dispatch) => (action: BackgroundAction) => { if (action.type === LIFTED_ACTION) toContentScript(action); + else if (action.type === TOGGLE_PERSIST) { + togglePersist(); + toMonitors({ + type: SET_PERSIST, + payload: !store.getState().instances.persisted, + }); + } return next(action); }; } diff --git a/extension/src/app/middlewares/panelSync.ts b/extension/src/app/middlewares/panelSync.ts index 558524c0..eb264802 100644 --- a/extension/src/app/middlewares/panelSync.ts +++ b/extension/src/app/middlewares/panelSync.ts @@ -2,6 +2,7 @@ import { LIFTED_ACTION, UPDATE_STATE, SELECT_INSTANCE, + TOGGLE_PERSIST, } from '@redux-devtools/app/lib/constants/actionTypes'; import { getActiveInstance } from '@redux-devtools/app/lib/reducers/instances'; import { Dispatch, MiddlewareAPI } from 'redux'; @@ -23,7 +24,7 @@ function panelDispatcher(bgConnection: chrome.runtime.Port) { next({ type: SELECT_INSTANCE, selected: connections[0] }); } } - if (action.type === LIFTED_ACTION) { + if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) { const instances = store.getState().instances; const instanceId = getActiveInstance(instances); const id = instances.options[instanceId].connectionId; diff --git a/extension/src/app/middlewares/windowSync.ts b/extension/src/app/middlewares/windowSync.ts index fb5cb549..6164f553 100644 --- a/extension/src/app/middlewares/windowSync.ts +++ b/extension/src/app/middlewares/windowSync.ts @@ -1,6 +1,7 @@ import { UPDATE_STATE, LIFTED_ACTION, + TOGGLE_PERSIST, } from '@redux-devtools/app/lib/constants/actionTypes'; import { getActiveInstance } from '@redux-devtools/app/lib/reducers/instances'; import { Dispatch, MiddlewareAPI, Store } from 'redux'; @@ -21,7 +22,7 @@ const syncStores = instances: baseStore.getState().instances, }); } - if (action.type === LIFTED_ACTION) { + if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) { const instances = store.getState().instances; const instanceId = getActiveInstance(instances); const id = instances.options[instanceId].connectionId; diff --git a/extension/src/app/reducers/window/instances.ts b/extension/src/app/reducers/window/instances.ts index 1db1a6ec..0d75d233 100644 --- a/extension/src/app/reducers/window/instances.ts +++ b/extension/src/app/reducers/window/instances.ts @@ -6,6 +6,7 @@ import { UPDATE_STATE, SELECT_INSTANCE, LIFTED_ACTION, + SET_PERSIST, } from '@redux-devtools/app/lib/constants/actionTypes'; import { ExpandedUpdateStateAction, @@ -27,6 +28,8 @@ export default function instances( return state; case SELECT_INSTANCE: return { ...state, selected: action.selected }; + case SET_PERSIST: + return { ...state, persisted: action.payload }; default: return state; } diff --git a/extension/src/app/stores/windowStore.ts b/extension/src/app/stores/windowStore.ts index 5e12ed97..26e73c97 100644 --- a/extension/src/app/stores/windowStore.ts +++ b/extension/src/app/stores/windowStore.ts @@ -66,16 +66,13 @@ export default function configureStore( ); } const store = createStore(persistedReducer, enhancer); - const persistor = persistStore(store); - - if ( - store.getState().connection.options.hostname && - store.getState().connection.options.port - ) { - store.dispatch({ - type: CONNECT_REQUEST, - }); - } + const persistor = persistStore(store, null, () => { + if (store.getState().connection.type !== 'disabled') { + store.dispatch({ + type: CONNECT_REQUEST, + }); + } + }); return { store, persistor }; } diff --git a/extension/src/browser/extension/inject/pageScript.ts b/extension/src/browser/extension/inject/pageScript.ts index 31c413f9..eec0472e 100644 --- a/extension/src/browser/extension/inject/pageScript.ts +++ b/extension/src/browser/extension/inject/pageScript.ts @@ -72,7 +72,7 @@ let reportId: string | null | undefined; function deprecateParam(oldParam: string, newParam: string) { /* eslint-disable no-console */ console.warn( - `${oldParam} parameter is deprecated, use ${newParam} instead: https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md` + `${oldParam} parameter is deprecated, use ${newParam} instead: https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/API/Arguments.md` ); /* eslint-enable no-console */ } @@ -84,8 +84,16 @@ export interface SerializeWithImmutable extends Serialize { export interface ConfigWithExpandedMaxAge { instanceId?: number; + /** + * @deprecated Use actionsDenylist instead. + */ readonly actionsBlacklist?: string | readonly string[]; + /** + * @deprecated Use actionsAllowlist instead. + */ readonly actionsWhitelist?: string | readonly string[]; + readonly actionsDenylist?: string | readonly string[]; + readonly actionsAllowlist?: string | readonly string[]; serialize?: boolean | SerializeWithImmutable; readonly serializeState?: | boolean @@ -213,6 +221,14 @@ function __REDUX_DEVTOOLS_EXTENSION__>( latency = 500, } = config; + // Deprecate actionsWhitelist and actionsBlacklist + if (config.actionsWhitelist) { + deprecateParam('actionsWhiteList', 'actionsAllowlist'); + } + if (config.actionsBlacklist) { + deprecateParam('actionsBlacklist', 'actionsDenylist'); + } + // Deprecate statesFilter and actionsFilter if (statesFilter) { deprecateParam('statesFilter', 'stateSanitizer'); diff --git a/extension/src/browser/extension/manifest.json b/extension/src/browser/extension/manifest.json index 33a5f74c..36cb428c 100644 --- a/extension/src/browser/extension/manifest.json +++ b/extension/src/browser/extension/manifest.json @@ -3,7 +3,7 @@ "name": "Redux DevTools", "short_name": "Redux DevTools", "description": "Redux DevTools for debugging application's state changes.", - "homepage_url": "https://github.com/zalmoxisus/redux-devtools-extension", + "homepage_url": "https://github.com/reduxjs/redux-devtools", "manifest_version": 2, "page_action": { "default_icon": "img/logo/gray.png", diff --git a/extension/src/browser/extension/options/FilterGroup.tsx b/extension/src/browser/extension/options/FilterGroup.tsx index 4bc24536..56c050f1 100644 --- a/extension/src/browser/extension/options/FilterGroup.tsx +++ b/extension/src/browser/extension/options/FilterGroup.tsx @@ -29,8 +29,8 @@ export default ({ options, saveOption }: OptionsProps) => { id="filter-hide" name="filter" type="radio" - checked={options.filter === FilterState.BLACKLIST_SPECIFIC} - onChange={() => saveOption('filter', FilterState.BLACKLIST_SPECIFIC)} + checked={options.filter === FilterState.DENYLIST_SPECIFIC} + onChange={() => saveOption('filter', FilterState.DENYLIST_SPECIFIC)} />