mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-25 19:13:56 +03:00
chore(core): convert to TypeScript (#655)
* Get started * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash * stash
This commit is contained in:
parent
94c2c28cad
commit
ee52c29a8d
|
@ -1 +1,2 @@
|
|||
export { default as tree } from './tree/tree';
|
||||
export type { InputOptions, NodeWithId } from './tree/tree';
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
} from './utils';
|
||||
import d3tooltip from 'd3tooltip';
|
||||
|
||||
interface InputOptions {
|
||||
export interface InputOptions {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
state?: {} | null;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
|
@ -34,7 +34,7 @@ interface InputOptions {
|
|||
widthBetweenNodesCoeff: number;
|
||||
transitionDuration: number;
|
||||
blinkDuration: number;
|
||||
onClickText: () => void;
|
||||
onClickText: (datum: NodeWithId) => void;
|
||||
tooltipOptions: {
|
||||
disabled?: boolean;
|
||||
left?: number | undefined;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as charts from './charts';
|
||||
|
||||
export { tree } from './charts';
|
||||
export type { InputOptions, NodeWithId } from './charts';
|
||||
|
||||
export default charts;
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export { default } from './Tabs';
|
||||
export { Tab } from './TabsHeader';
|
||||
|
|
|
@ -6,7 +6,7 @@ export { default as Editor } from './Editor';
|
|||
export { default as Form } from './Form';
|
||||
export { default as Select } from './Select';
|
||||
export { default as Slider } from './Slider';
|
||||
export { default as Tabs } from './Tabs';
|
||||
export { default as Tabs, Tab } from './Tabs';
|
||||
export { default as SegmentedControl } from './SegmentedControl';
|
||||
export { default as Notification } from './Notification';
|
||||
export * from './Toolbar';
|
||||
|
@ -14,3 +14,4 @@ export * from './Toolbar';
|
|||
import color from './utils/color';
|
||||
export const effects = { color };
|
||||
export { default as createStyledComponent } from './utils/createStyledComponent';
|
||||
export { Theme, ThemeFromProvider, Scheme } from './utils/theme';
|
||||
|
|
|
@ -3,19 +3,22 @@ import { nicinabox as defaultDarkScheme } from 'redux-devtools-themes';
|
|||
import * as baseSchemes from 'base16';
|
||||
import * as additionalSchemes from '../colorSchemes';
|
||||
import invertColors from '../utils/invertColors';
|
||||
import { Theme } from '../themes/default';
|
||||
import { Theme as ThemeBase } from '../themes/default';
|
||||
|
||||
export const schemes = { ...baseSchemes, ...additionalSchemes };
|
||||
export const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule`
|
||||
export const listThemes = () => Object.keys(themes);
|
||||
|
||||
export type Theme = keyof typeof themes;
|
||||
export type Scheme = keyof typeof schemes;
|
||||
|
||||
export interface ThemeData {
|
||||
theme: keyof typeof themes;
|
||||
scheme: keyof typeof schemes;
|
||||
light: boolean;
|
||||
}
|
||||
|
||||
export interface ThemeFromProvider extends Theme {
|
||||
export interface ThemeFromProvider extends ThemeBase {
|
||||
type: keyof typeof themes;
|
||||
light: boolean;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import * as themes from 'redux-devtools-themes';
|
|||
import { Base16Theme } from 'react-base16-styling';
|
||||
import { ChartMonitorState } from './reducers';
|
||||
import { Primitive } from 'd3';
|
||||
import { NodeWithId } from 'd3-state-visualizer/lib/charts/tree/tree';
|
||||
|
||||
const wrapperStyle = {
|
||||
width: '100%',
|
||||
|
@ -25,6 +26,7 @@ export interface Props<S, A extends Action<unknown>>
|
|||
isSorted: boolean;
|
||||
heightBetweenNodesCoeff: number;
|
||||
widthBetweenNodesCoeff: number;
|
||||
onClickText: (datum: NodeWithId) => void;
|
||||
tooltipOptions: {
|
||||
disabled: boolean;
|
||||
offset: {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Base16Theme } from 'react-base16-styling';
|
|||
import reducer, { ChartMonitorState } from './reducers';
|
||||
import Chart, { Props } from './Chart';
|
||||
import { Primitive } from 'd3';
|
||||
import { NodeWithId } from 'd3-state-visualizer/lib/charts/tree/tree';
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const { reset, rollback, commit, sweep, toggleAction } = ActionCreators;
|
||||
|
||||
|
@ -49,6 +50,7 @@ export interface ChartMonitorProps<S, A extends Action<unknown>>
|
|||
isSorted: boolean;
|
||||
heightBetweenNodesCoeff: number;
|
||||
widthBetweenNodesCoeff: number;
|
||||
onClickText: (datum: NodeWithId) => void;
|
||||
tooltipOptions: unknown;
|
||||
style: {
|
||||
width: number;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
],
|
||||
"plugins": ["@babel/plugin-proposal-class-properties"]
|
||||
}
|
||||
|
|
2
packages/redux-devtools-core/.eslintignore
Normal file
2
packages/redux-devtools-core/.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
lib
|
||||
umd
|
29
packages/redux-devtools-core/.eslintrc.js
Normal file
29
packages/redux-devtools-core/.eslintrc.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
module.exports = {
|
||||
extends: '../../.eslintrc',
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['test/*.ts', 'test/*.tsx'],
|
||||
extends: '../../eslintrc.ts.react.jest.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./test/tsconfig.json'],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['webpack.config.ts', 'webpack.config.umd.ts'],
|
||||
extends: '../../eslintrc.ts.base.json',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.webpack.json'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
4
packages/redux-devtools-core/jest.config.js
Normal file
4
packages/redux-devtools-core/jest.config.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
|
||||
};
|
|
@ -2,65 +2,39 @@
|
|||
"name": "redux-devtools-core",
|
||||
"version": "1.0.0-4",
|
||||
"description": "Reusable functions of Redux DevTools",
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --hot --inline --env.development --env.platform=web --progress",
|
||||
"build:web": "rimraf ./build/web && webpack -p --env.platform=web --progress",
|
||||
"build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.js",
|
||||
"build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js",
|
||||
"build": "rimraf ./lib && babel ./src/app --out-dir lib",
|
||||
"clean": "rimraf lib",
|
||||
"test": "jest --no-cache",
|
||||
"prepare": "npm run build && npm run build:umd && npm run build:umd:min",
|
||||
"prepublishOnly": "npm run test && npm run build && npm run build:umd && npm run build:umd:min"
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-core",
|
||||
"bugs": {
|
||||
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"license": "MIT",
|
||||
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||
"files": [
|
||||
"src",
|
||||
"lib",
|
||||
"umd"
|
||||
],
|
||||
"jest": {
|
||||
"setupFilesAfterEnv": [
|
||||
"<rootDir>/test/setup.js"
|
||||
],
|
||||
"moduleNameMapper": {
|
||||
"\\.(css|scss)$": "<rootDir>/test/__mocks__/styleMock.js"
|
||||
}
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||
},
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.10.5",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"babel-loader": "^8.1.0",
|
||||
"css-loader": "^4.2.1",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.3",
|
||||
"enzyme-to-json": "^3.5.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"html-loader": "^1.1.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"jest": "^26.2.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"style-loader": "^1.2.1",
|
||||
"url-loader": "^4.1.0",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-hot-middleware": "^2.25.0"
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --hot --inline --env.development --env.platform=web --progress",
|
||||
"build": "npm run build:types && npm run build:js && npm run build:web && npm run build:umd && npm run build:umd:min",
|
||||
"build:types": "tsc --emitDeclarationOnly",
|
||||
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
|
||||
"build:web": "rimraf ./build/web && webpack -p --env.platform=web --progress",
|
||||
"build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.ts",
|
||||
"build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts",
|
||||
"clean": "rimraf lib",
|
||||
"test": "jest",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"type-check": "tsc --noEmit",
|
||||
"type-check:watch": "npm run type-check -- --watch",
|
||||
"preversion": "npm run type-check && npm run lint && npm run test",
|
||||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3-state-visualizer": "^1.3.4",
|
||||
|
@ -90,6 +64,34 @@
|
|||
"socketcluster-client": "^14.3.1",
|
||||
"styled-components": "^5.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.10.5",
|
||||
"@babel/core": "^7.11.1",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
||||
"@babel/preset-env": "^7.11.0",
|
||||
"@babel/preset-react": "^7.10.4",
|
||||
"@rjsf/core": "^2.4.0",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"@types/socketcluster-client": "^13.0.3",
|
||||
"babel-loader": "^8.1.0",
|
||||
"css-loader": "^4.2.1",
|
||||
"enzyme": "^3.11.0",
|
||||
"enzyme-adapter-react-16": "^1.15.3",
|
||||
"enzyme-to-json": "^3.5.0",
|
||||
"file-loader": "^6.0.0",
|
||||
"html-loader": "^1.1.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
"jest": "^26.2.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"style-loader": "^1.2.1",
|
||||
"url-loader": "^4.1.0",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-hot-middleware": "^2.25.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0"
|
||||
}
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
import {
|
||||
CHANGE_SECTION,
|
||||
CHANGE_THEME,
|
||||
SELECT_INSTANCE,
|
||||
SELECT_MONITOR,
|
||||
UPDATE_MONITOR_STATE,
|
||||
LIFTED_ACTION,
|
||||
MONITOR_ACTION,
|
||||
EXPORT,
|
||||
TOGGLE_SYNC,
|
||||
TOGGLE_SLIDER,
|
||||
TOGGLE_DISPATCHER,
|
||||
TOGGLE_PERSIST,
|
||||
GET_REPORT_REQUEST,
|
||||
SHOW_NOTIFICATION,
|
||||
CLEAR_NOTIFICATION,
|
||||
} from '../constants/actionTypes';
|
||||
import { RECONNECT } from '../constants/socketActionTypes';
|
||||
|
||||
let monitorReducer;
|
||||
let monitorProps = {};
|
||||
|
||||
export function changeSection(section) {
|
||||
return { type: CHANGE_SECTION, section };
|
||||
}
|
||||
|
||||
export function changeTheme(data) {
|
||||
return { type: CHANGE_THEME, ...data.formData };
|
||||
}
|
||||
|
||||
export function liftedDispatch(action) {
|
||||
if (action.type[0] === '@') {
|
||||
if (action.type === '@@INIT_MONITOR') {
|
||||
monitorReducer = action.update;
|
||||
monitorProps = action.monitorProps;
|
||||
}
|
||||
return { type: MONITOR_ACTION, action, monitorReducer, monitorProps };
|
||||
}
|
||||
return { type: LIFTED_ACTION, message: 'DISPATCH', action };
|
||||
}
|
||||
|
||||
export function selectInstance(selected) {
|
||||
return { type: SELECT_INSTANCE, selected };
|
||||
}
|
||||
|
||||
export function selectMonitor(monitor) {
|
||||
return { type: SELECT_MONITOR, monitor };
|
||||
}
|
||||
|
||||
export function selectMonitorWithState(value, monitorState) {
|
||||
return { type: SELECT_MONITOR, monitor: value, monitorState };
|
||||
}
|
||||
|
||||
export function selectMonitorTab(subTabName) {
|
||||
return { type: UPDATE_MONITOR_STATE, nextState: { subTabName } };
|
||||
}
|
||||
|
||||
export function updateMonitorState(nextState) {
|
||||
return { type: UPDATE_MONITOR_STATE, nextState };
|
||||
}
|
||||
|
||||
export function importState(state, preloadedState) {
|
||||
return { type: LIFTED_ACTION, message: 'IMPORT', state, preloadedState };
|
||||
}
|
||||
|
||||
export function exportState() {
|
||||
return { type: EXPORT };
|
||||
}
|
||||
|
||||
export function lockChanges(status) {
|
||||
return {
|
||||
type: LIFTED_ACTION,
|
||||
message: 'DISPATCH',
|
||||
action: { type: 'LOCK_CHANGES', status },
|
||||
toAll: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function pauseRecording(status) {
|
||||
return {
|
||||
type: LIFTED_ACTION,
|
||||
message: 'DISPATCH',
|
||||
action: { type: 'PAUSE_RECORDING', status },
|
||||
toAll: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function dispatchRemotely(action) {
|
||||
return { type: LIFTED_ACTION, message: 'ACTION', action };
|
||||
}
|
||||
|
||||
export function togglePersist() {
|
||||
return { type: TOGGLE_PERSIST };
|
||||
}
|
||||
|
||||
export function toggleSync() {
|
||||
return { type: TOGGLE_SYNC };
|
||||
}
|
||||
|
||||
export function toggleSlider() {
|
||||
return { type: TOGGLE_SLIDER };
|
||||
}
|
||||
|
||||
export function toggleDispatcher() {
|
||||
return { type: TOGGLE_DISPATCHER };
|
||||
}
|
||||
|
||||
export function saveSocketSettings(options) {
|
||||
return { type: RECONNECT, options };
|
||||
}
|
||||
|
||||
export function showNotification(message) {
|
||||
return { type: SHOW_NOTIFICATION, notification: { type: 'error', message } };
|
||||
}
|
||||
|
||||
export function clearNotification() {
|
||||
return { type: CLEAR_NOTIFICATION };
|
||||
}
|
||||
|
||||
export function getReport(report) {
|
||||
return { type: GET_REPORT_REQUEST, report };
|
||||
}
|
573
packages/redux-devtools-core/src/app/actions/index.ts
Normal file
573
packages/redux-devtools-core/src/app/actions/index.ts
Normal file
|
@ -0,0 +1,573 @@
|
|||
import { Scheme, Theme } from 'devui';
|
||||
import { AuthStates, States } from 'socketcluster-client/lib/scclientsocket';
|
||||
import {
|
||||
CHANGE_SECTION,
|
||||
CHANGE_THEME,
|
||||
SELECT_INSTANCE,
|
||||
SELECT_MONITOR,
|
||||
UPDATE_MONITOR_STATE,
|
||||
LIFTED_ACTION,
|
||||
MONITOR_ACTION,
|
||||
EXPORT,
|
||||
TOGGLE_SYNC,
|
||||
TOGGLE_SLIDER,
|
||||
TOGGLE_DISPATCHER,
|
||||
TOGGLE_PERSIST,
|
||||
GET_REPORT_REQUEST,
|
||||
SHOW_NOTIFICATION,
|
||||
CLEAR_NOTIFICATION,
|
||||
UPDATE_STATE,
|
||||
UPDATE_REPORTS,
|
||||
REMOVE_INSTANCE,
|
||||
SET_STATE,
|
||||
GET_REPORT_ERROR,
|
||||
GET_REPORT_SUCCESS,
|
||||
ERROR,
|
||||
} from '../constants/actionTypes';
|
||||
import {
|
||||
AUTH_ERROR,
|
||||
AUTH_REQUEST,
|
||||
AUTH_SUCCESS,
|
||||
CONNECT_ERROR,
|
||||
CONNECT_REQUEST,
|
||||
CONNECT_SUCCESS,
|
||||
DEAUTHENTICATE,
|
||||
DISCONNECTED,
|
||||
EMIT,
|
||||
RECONNECT,
|
||||
SUBSCRIBE_ERROR,
|
||||
SUBSCRIBE_REQUEST,
|
||||
SUBSCRIBE_SUCCESS,
|
||||
UNSUBSCRIBE,
|
||||
} from '../constants/socketActionTypes';
|
||||
import { Action } from 'redux';
|
||||
import { Features, State } from '../reducers/instances';
|
||||
import { MonitorStateMonitorState } from '../reducers/monitor';
|
||||
import { LiftedAction } from 'redux-devtools-instrument';
|
||||
import { Data } from '../reducers/reports';
|
||||
|
||||
let monitorReducer: (
|
||||
monitorProps: unknown,
|
||||
state: unknown | undefined,
|
||||
action: Action<unknown>
|
||||
) => unknown;
|
||||
let monitorProps: unknown = {};
|
||||
|
||||
interface ChangeSectionAction {
|
||||
readonly type: typeof CHANGE_SECTION;
|
||||
readonly section: string;
|
||||
}
|
||||
export function changeSection(section: string): ChangeSectionAction {
|
||||
return { type: CHANGE_SECTION, section };
|
||||
}
|
||||
|
||||
interface ChangeThemeFormData {
|
||||
readonly theme: Theme;
|
||||
readonly scheme: Scheme;
|
||||
readonly dark: boolean;
|
||||
}
|
||||
interface ChangeThemeData {
|
||||
readonly formData: ChangeThemeFormData;
|
||||
}
|
||||
interface ChangeThemeAction {
|
||||
readonly type: typeof CHANGE_THEME;
|
||||
readonly theme: Theme;
|
||||
readonly scheme: Scheme;
|
||||
readonly dark: boolean;
|
||||
}
|
||||
export function changeTheme(data: ChangeThemeData): ChangeThemeAction {
|
||||
return { type: CHANGE_THEME, ...data.formData };
|
||||
}
|
||||
|
||||
export interface InitMonitorAction {
|
||||
type: '@@INIT_MONITOR';
|
||||
newMonitorState: unknown;
|
||||
update: (
|
||||
monitorProps: unknown,
|
||||
state: unknown | undefined,
|
||||
action: Action<unknown>
|
||||
) => unknown;
|
||||
monitorProps: unknown;
|
||||
}
|
||||
export interface MonitorActionAction {
|
||||
type: typeof MONITOR_ACTION;
|
||||
action: InitMonitorAction;
|
||||
monitorReducer: (
|
||||
monitorProps: unknown,
|
||||
state: unknown | undefined,
|
||||
action: Action<unknown>
|
||||
) => unknown;
|
||||
monitorProps: unknown;
|
||||
}
|
||||
export interface JumpToStateAction {
|
||||
type: 'JUMP_TO_STATE';
|
||||
index: number;
|
||||
actionId: number;
|
||||
}
|
||||
export interface JumpToActionAction {
|
||||
type: 'JUMP_TO_ACTION';
|
||||
index: number;
|
||||
actionId: number;
|
||||
}
|
||||
export interface PauseRecordingAction {
|
||||
type: 'PAUSE_RECORDING';
|
||||
status: boolean;
|
||||
}
|
||||
export interface LockChangesAction {
|
||||
type: 'LOCK_CHANGES';
|
||||
status: boolean;
|
||||
}
|
||||
export interface ToggleActionAction {
|
||||
type: 'TOGGLE_ACTION';
|
||||
}
|
||||
export interface RollbackAction {
|
||||
type: 'ROLLBACK';
|
||||
}
|
||||
export interface SweepAction {
|
||||
type: 'SWEEP';
|
||||
}
|
||||
export type DispatchAction =
|
||||
| JumpToStateAction
|
||||
| JumpToActionAction
|
||||
| PauseRecordingAction
|
||||
| LockChangesAction
|
||||
| ToggleActionAction
|
||||
| RollbackAction
|
||||
| SweepAction;
|
||||
interface LiftedActionActionBase {
|
||||
action?: DispatchAction | string | CustomAction;
|
||||
state?: string;
|
||||
toAll?: boolean;
|
||||
}
|
||||
export interface LiftedActionDispatchAction extends LiftedActionActionBase {
|
||||
type: typeof LIFTED_ACTION;
|
||||
message: 'DISPATCH';
|
||||
action: DispatchAction;
|
||||
toAll?: boolean;
|
||||
}
|
||||
interface LiftedActionImportAction extends LiftedActionActionBase {
|
||||
type: typeof LIFTED_ACTION;
|
||||
message: 'IMPORT';
|
||||
state: string;
|
||||
preloadedState: unknown | undefined;
|
||||
}
|
||||
interface LiftedActionActionAction extends LiftedActionActionBase {
|
||||
type: typeof LIFTED_ACTION;
|
||||
message: 'ACTION';
|
||||
action: string | CustomAction;
|
||||
}
|
||||
interface LiftedActionExportAction extends LiftedActionActionBase {
|
||||
type: typeof LIFTED_ACTION;
|
||||
message: 'EXPORT';
|
||||
toExport: boolean;
|
||||
}
|
||||
export type LiftedActionAction =
|
||||
| LiftedActionDispatchAction
|
||||
| LiftedActionImportAction
|
||||
| LiftedActionActionAction
|
||||
| LiftedActionExportAction;
|
||||
export function liftedDispatch(
|
||||
action:
|
||||
| InitMonitorAction
|
||||
| JumpToStateAction
|
||||
| JumpToActionAction
|
||||
| LiftedAction<unknown, Action<unknown>, unknown>
|
||||
): MonitorActionAction | LiftedActionDispatchAction {
|
||||
if (action.type[0] === '@') {
|
||||
if (action.type === '@@INIT_MONITOR') {
|
||||
monitorReducer = action.update;
|
||||
monitorProps = action.monitorProps;
|
||||
}
|
||||
return {
|
||||
type: MONITOR_ACTION,
|
||||
action,
|
||||
monitorReducer,
|
||||
monitorProps,
|
||||
} as MonitorActionAction;
|
||||
}
|
||||
return {
|
||||
type: LIFTED_ACTION,
|
||||
message: 'DISPATCH',
|
||||
action,
|
||||
} as LiftedActionDispatchAction;
|
||||
}
|
||||
|
||||
interface SelectInstanceAction {
|
||||
type: typeof SELECT_INSTANCE;
|
||||
selected: string;
|
||||
}
|
||||
export function selectInstance(selected: string): SelectInstanceAction {
|
||||
return { type: SELECT_INSTANCE, selected };
|
||||
}
|
||||
|
||||
interface SelectMonitorAction {
|
||||
type: typeof SELECT_MONITOR;
|
||||
monitor: string;
|
||||
monitorState?: MonitorStateMonitorState;
|
||||
}
|
||||
export function selectMonitor(monitor: string): SelectMonitorAction {
|
||||
return { type: SELECT_MONITOR, monitor };
|
||||
}
|
||||
export function selectMonitorWithState(
|
||||
value: string,
|
||||
monitorState: MonitorStateMonitorState
|
||||
): SelectMonitorAction {
|
||||
return { type: SELECT_MONITOR, monitor: value, monitorState };
|
||||
}
|
||||
|
||||
interface NextState {
|
||||
subTabName: string;
|
||||
inspectedStatePath?: string[];
|
||||
}
|
||||
interface UpdateMonitorStateAction {
|
||||
type: typeof UPDATE_MONITOR_STATE;
|
||||
nextState: NextState;
|
||||
}
|
||||
export function selectMonitorTab(subTabName: string): UpdateMonitorStateAction {
|
||||
return { type: UPDATE_MONITOR_STATE, nextState: { subTabName } };
|
||||
}
|
||||
|
||||
export function updateMonitorState(
|
||||
nextState: NextState
|
||||
): UpdateMonitorStateAction {
|
||||
return { type: UPDATE_MONITOR_STATE, nextState };
|
||||
}
|
||||
|
||||
export function importState(
|
||||
state: string,
|
||||
preloadedState?: unknown
|
||||
): LiftedActionImportAction {
|
||||
return { type: LIFTED_ACTION, message: 'IMPORT', state, preloadedState };
|
||||
}
|
||||
|
||||
interface ExportAction {
|
||||
type: typeof EXPORT;
|
||||
}
|
||||
export function exportState(): ExportAction {
|
||||
return { type: EXPORT };
|
||||
}
|
||||
|
||||
export function lockChanges(status: boolean): LiftedActionDispatchAction {
|
||||
return {
|
||||
type: LIFTED_ACTION,
|
||||
message: 'DISPATCH',
|
||||
action: { type: 'LOCK_CHANGES', status },
|
||||
toAll: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function pauseRecording(status: boolean): LiftedActionDispatchAction {
|
||||
return {
|
||||
type: LIFTED_ACTION,
|
||||
message: 'DISPATCH',
|
||||
action: { type: 'PAUSE_RECORDING', status },
|
||||
toAll: true,
|
||||
};
|
||||
}
|
||||
|
||||
export interface CustomAction {
|
||||
name: string;
|
||||
selected: number;
|
||||
args: (string | undefined)[];
|
||||
rest: string;
|
||||
}
|
||||
export function dispatchRemotely(
|
||||
action: string | CustomAction
|
||||
): LiftedActionActionAction {
|
||||
return { type: LIFTED_ACTION, message: 'ACTION', action };
|
||||
}
|
||||
|
||||
interface TogglePersistAction {
|
||||
type: typeof TOGGLE_PERSIST;
|
||||
}
|
||||
export function togglePersist(): TogglePersistAction {
|
||||
return { type: TOGGLE_PERSIST };
|
||||
}
|
||||
|
||||
interface ToggleSyncAction {
|
||||
type: typeof TOGGLE_SYNC;
|
||||
}
|
||||
export function toggleSync(): ToggleSyncAction {
|
||||
return { type: TOGGLE_SYNC };
|
||||
}
|
||||
|
||||
interface ToggleSliderAction {
|
||||
type: typeof TOGGLE_SLIDER;
|
||||
}
|
||||
export function toggleSlider(): ToggleSliderAction {
|
||||
return { type: TOGGLE_SLIDER };
|
||||
}
|
||||
|
||||
interface ToggleDispatcherAction {
|
||||
type: typeof TOGGLE_DISPATCHER;
|
||||
}
|
||||
export function toggleDispatcher(): ToggleDispatcherAction {
|
||||
return { type: TOGGLE_DISPATCHER };
|
||||
}
|
||||
|
||||
export type ConnectionType = 'disabled' | 'remotedev' | 'custom';
|
||||
export interface ConnectionOptions {
|
||||
readonly type: ConnectionType;
|
||||
readonly hostname: string;
|
||||
readonly port: number;
|
||||
readonly secure: boolean;
|
||||
}
|
||||
interface ReconnectAction {
|
||||
readonly type: typeof RECONNECT;
|
||||
readonly options: ConnectionOptions;
|
||||
}
|
||||
export function saveSocketSettings(
|
||||
options: ConnectionOptions
|
||||
): ReconnectAction {
|
||||
return { type: RECONNECT, options };
|
||||
}
|
||||
|
||||
interface Notification {
|
||||
readonly type: 'error';
|
||||
readonly message: string;
|
||||
}
|
||||
interface ShowNotificationAction {
|
||||
readonly type: typeof SHOW_NOTIFICATION;
|
||||
readonly notification: Notification;
|
||||
}
|
||||
export function showNotification(message: string): ShowNotificationAction {
|
||||
return { type: SHOW_NOTIFICATION, notification: { type: 'error', message } };
|
||||
}
|
||||
|
||||
interface ClearNotificationAction {
|
||||
readonly type: typeof CLEAR_NOTIFICATION;
|
||||
}
|
||||
export function clearNotification(): ClearNotificationAction {
|
||||
return { type: CLEAR_NOTIFICATION };
|
||||
}
|
||||
|
||||
interface GetReportRequest {
|
||||
readonly type: typeof GET_REPORT_REQUEST;
|
||||
readonly report: unknown;
|
||||
}
|
||||
export function getReport(report: unknown): GetReportRequest {
|
||||
return { type: GET_REPORT_REQUEST, report };
|
||||
}
|
||||
|
||||
export interface ActionCreator {
|
||||
args: string[];
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface LibConfig {
|
||||
actionCreators?: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
features?: Features;
|
||||
serialize?: boolean;
|
||||
}
|
||||
|
||||
export interface RequestBase {
|
||||
id: string;
|
||||
instanceId?: string;
|
||||
action?: string;
|
||||
name?: string;
|
||||
libConfig?: LibConfig;
|
||||
actionsById?: string;
|
||||
computedStates?: string;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
payload?: {} | string;
|
||||
liftedState?: Partial<State>;
|
||||
}
|
||||
interface InitRequest extends RequestBase {
|
||||
type: 'INIT';
|
||||
action: string;
|
||||
}
|
||||
interface ActionRequest extends RequestBase {
|
||||
type: 'ACTION';
|
||||
isExcess: boolean;
|
||||
nextActionId: number;
|
||||
maxAge: number;
|
||||
batched: boolean;
|
||||
}
|
||||
interface StateRequest extends RequestBase {
|
||||
type: 'STATE';
|
||||
committedState: unknown;
|
||||
}
|
||||
interface PartialStateRequest extends RequestBase {
|
||||
type: 'PARTIAL_STATE';
|
||||
committedState: unknown;
|
||||
maxAge: number;
|
||||
}
|
||||
interface LiftedRequest extends RequestBase {
|
||||
type: 'LIFTED';
|
||||
}
|
||||
export interface ExportRequest extends RequestBase {
|
||||
type: 'EXPORT';
|
||||
committedState: unknown;
|
||||
}
|
||||
export type Request =
|
||||
| InitRequest
|
||||
| ActionRequest
|
||||
| StateRequest
|
||||
| PartialStateRequest
|
||||
| LiftedRequest
|
||||
| ExportRequest;
|
||||
|
||||
interface UpdateStateAction {
|
||||
type: typeof UPDATE_STATE;
|
||||
request?: Request;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
interface SetStateAction {
|
||||
type: typeof SET_STATE;
|
||||
newState: State;
|
||||
}
|
||||
|
||||
interface RemoveInstanceAction {
|
||||
type: typeof REMOVE_INSTANCE;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface ConnectRequestAction {
|
||||
type: typeof CONNECT_REQUEST;
|
||||
options: ConnectionOptions;
|
||||
}
|
||||
|
||||
interface ConnectSuccessPayload {
|
||||
id: string;
|
||||
authState: AuthStates;
|
||||
socketState: States;
|
||||
}
|
||||
interface ConnectSuccessAction {
|
||||
type: typeof CONNECT_SUCCESS;
|
||||
payload: ConnectSuccessPayload;
|
||||
error: Error | undefined;
|
||||
}
|
||||
|
||||
interface ConnectErrorAction {
|
||||
type: typeof CONNECT_ERROR;
|
||||
error: Error | undefined;
|
||||
}
|
||||
|
||||
interface AuthRequestAction {
|
||||
type: typeof AUTH_REQUEST;
|
||||
}
|
||||
|
||||
interface AuthSuccessAction {
|
||||
type: typeof AUTH_SUCCESS;
|
||||
baseChannel: string;
|
||||
}
|
||||
|
||||
interface AuthErrorAction {
|
||||
type: typeof AUTH_ERROR;
|
||||
error: Error;
|
||||
}
|
||||
|
||||
interface DisconnectedAction {
|
||||
type: typeof DISCONNECTED;
|
||||
code: number;
|
||||
}
|
||||
|
||||
interface DeauthenticateAction {
|
||||
type: typeof DEAUTHENTICATE;
|
||||
}
|
||||
|
||||
interface SubscribeRequestAction {
|
||||
type: typeof SUBSCRIBE_REQUEST;
|
||||
channel: string;
|
||||
subscription: typeof UPDATE_STATE | typeof UPDATE_REPORTS;
|
||||
}
|
||||
|
||||
interface SubscribeSuccessAction {
|
||||
type: typeof SUBSCRIBE_SUCCESS;
|
||||
channel: string;
|
||||
}
|
||||
|
||||
interface SubscribeErrorAction {
|
||||
type: typeof SUBSCRIBE_ERROR;
|
||||
error: Error;
|
||||
status: string;
|
||||
}
|
||||
|
||||
interface UnsubscribeAction {
|
||||
type: typeof UNSUBSCRIBE;
|
||||
channel: string;
|
||||
}
|
||||
|
||||
export interface EmitAction {
|
||||
type: typeof EMIT;
|
||||
message: string;
|
||||
id?: string | false;
|
||||
instanceId?: string;
|
||||
action?: unknown;
|
||||
state?: unknown;
|
||||
}
|
||||
|
||||
interface ListRequest {
|
||||
type: 'list';
|
||||
data: Data[];
|
||||
}
|
||||
interface AddRequest {
|
||||
type: 'add';
|
||||
data: Data;
|
||||
}
|
||||
interface RemoveRequest {
|
||||
type: 'remove';
|
||||
data: Data;
|
||||
id: unknown;
|
||||
}
|
||||
export type UpdateReportsRequest = ListRequest | AddRequest | RemoveRequest;
|
||||
interface UpdateReportsAction {
|
||||
type: typeof UPDATE_REPORTS;
|
||||
request: UpdateReportsRequest;
|
||||
}
|
||||
|
||||
interface GetReportError {
|
||||
type: typeof GET_REPORT_ERROR;
|
||||
error: Error;
|
||||
}
|
||||
|
||||
interface GetReportSuccess {
|
||||
type: typeof GET_REPORT_SUCCESS;
|
||||
data: { payload: string };
|
||||
}
|
||||
|
||||
interface ErrorAction {
|
||||
type: typeof ERROR;
|
||||
payload: string;
|
||||
}
|
||||
|
||||
export type StoreAction =
|
||||
| ChangeSectionAction
|
||||
| ChangeThemeAction
|
||||
| MonitorActionAction
|
||||
| LiftedActionAction
|
||||
| SelectInstanceAction
|
||||
| SelectMonitorAction
|
||||
| UpdateMonitorStateAction
|
||||
| ExportAction
|
||||
| TogglePersistAction
|
||||
| ToggleSyncAction
|
||||
| ToggleSliderAction
|
||||
| ToggleDispatcherAction
|
||||
| ReconnectAction
|
||||
| ShowNotificationAction
|
||||
| ClearNotificationAction
|
||||
| GetReportRequest
|
||||
| SetStateAction
|
||||
| UpdateStateAction
|
||||
| RemoveInstanceAction
|
||||
| ConnectRequestAction
|
||||
| ConnectSuccessAction
|
||||
| ConnectErrorAction
|
||||
| AuthRequestAction
|
||||
| AuthSuccessAction
|
||||
| AuthErrorAction
|
||||
| DisconnectedAction
|
||||
| DeauthenticateAction
|
||||
| SubscribeRequestAction
|
||||
| SubscribeSuccessAction
|
||||
| SubscribeErrorAction
|
||||
| UnsubscribeAction
|
||||
| EmitAction
|
||||
| UpdateReportsAction
|
||||
| GetReportError
|
||||
| GetReportSuccess
|
||||
| ErrorAction;
|
|
@ -8,15 +8,22 @@ import PrintButton from './buttons/PrintButton';
|
|||
import DispatcherButton from './buttons/DispatcherButton';
|
||||
import SliderButton from './buttons/SliderButton';
|
||||
import MonitorSelector from './MonitorSelector';
|
||||
import { Options } from '../reducers/instances';
|
||||
|
||||
export default class BottomButtons extends Component {
|
||||
interface Props {
|
||||
dispatcherIsOpen: boolean;
|
||||
sliderIsOpen: boolean;
|
||||
options: Options;
|
||||
}
|
||||
|
||||
export default class BottomButtons extends Component<Props> {
|
||||
static propTypes = {
|
||||
dispatcherIsOpen: PropTypes.bool,
|
||||
sliderIsOpen: PropTypes.bool,
|
||||
options: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return (
|
||||
nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen ||
|
||||
nextProps.sliderIsOpen !== this.props.sliderIsOpen ||
|
|
@ -1,8 +1,6 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Tabs, Toolbar, Button, Divider } from 'devui';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { GoBook } from 'react-icons/go';
|
||||
import { IoMdText } from 'react-icons/io';
|
||||
import { TiSocialTwitter } from 'react-icons/ti';
|
||||
|
@ -11,13 +9,14 @@ import { changeSection } from '../actions';
|
|||
|
||||
const tabs = [{ name: 'Actions' }, { name: 'Reports' }, { name: 'Settings' }];
|
||||
|
||||
class Header extends Component {
|
||||
static propTypes = {
|
||||
section: PropTypes.string.isRequired,
|
||||
changeSection: PropTypes.func.isRequired,
|
||||
};
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
interface OwnProps {
|
||||
readonly section: string;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
openLink = (url) => () => {
|
||||
class Header extends Component<Props> {
|
||||
openLink = (url: string) => () => {
|
||||
window.open(url);
|
||||
};
|
||||
|
||||
|
@ -69,10 +68,8 @@ class Header extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
changeSection: bindActionCreators(changeSection, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
changeSection,
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(Header);
|
||||
export default connect(null, actionCreators)(Header);
|
|
@ -1,48 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Select } from 'devui';
|
||||
import { selectInstance } from '../actions';
|
||||
|
||||
class InstanceSelector extends Component {
|
||||
static propTypes = {
|
||||
selected: PropTypes.string,
|
||||
instances: PropTypes.object.isRequired,
|
||||
onSelect: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
this.select = [{ value: '', label: 'Autoselect instances' }];
|
||||
const instances = this.props.instances;
|
||||
let name;
|
||||
Object.keys(instances).forEach((key) => {
|
||||
name = instances[key].name;
|
||||
if (name !== undefined)
|
||||
this.select.push({ value: key, label: instances[key].name });
|
||||
});
|
||||
|
||||
return (
|
||||
<Select
|
||||
options={this.select}
|
||||
onChange={this.props.onSelect}
|
||||
value={this.props.selected || ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
selected: state.instances.selected,
|
||||
instances: state.instances.options,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
onSelect: bindActionCreators(selectInstance, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(InstanceSelector);
|
|
@ -0,0 +1,43 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Select } from 'devui';
|
||||
import { selectInstance } from '../actions';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
class InstanceSelector extends Component<Props> {
|
||||
select?: { readonly value: string; readonly label: string }[];
|
||||
|
||||
render() {
|
||||
this.select = [{ value: '', label: 'Autoselect instances' }];
|
||||
const instances = this.props.instances;
|
||||
let name;
|
||||
Object.keys(instances).forEach((key) => {
|
||||
name = instances[key].name;
|
||||
if (name !== undefined) this.select!.push({ value: key, label: name });
|
||||
});
|
||||
|
||||
return (
|
||||
<Select
|
||||
options={this.select}
|
||||
// TODO Where's the type-checking?
|
||||
onChange={this.props.onSelect}
|
||||
value={this.props.selected || ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
selected: state.instances.selected,
|
||||
instances: state.instances.options,
|
||||
});
|
||||
|
||||
const actionCreators = {
|
||||
onSelect: selectInstance,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actionCreators)(InstanceSelector);
|
|
@ -1,45 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Tabs } from 'devui';
|
||||
import { monitors } from '../utils/getMonitor';
|
||||
import { selectMonitor } from '../actions';
|
||||
|
||||
class MonitorSelector extends Component {
|
||||
static propTypes = {
|
||||
selected: PropTypes.string,
|
||||
selectMonitor: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.selected !== this.props.selected;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Tabs
|
||||
main
|
||||
collapsible
|
||||
position="center"
|
||||
tabs={monitors}
|
||||
onClick={this.props.selectMonitor}
|
||||
selected={this.props.selected || 'InspectorMonitor'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
selected: state.monitor.selected,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
selectMonitor: bindActionCreators(selectMonitor, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(MonitorSelector);
|
|
@ -0,0 +1,39 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Tabs } from 'devui';
|
||||
import { monitors } from '../utils/getMonitor';
|
||||
import { selectMonitor } from '../actions';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
class MonitorSelector extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.selected !== this.props.selected;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Tabs
|
||||
main
|
||||
collapsible
|
||||
position="center"
|
||||
tabs={monitors}
|
||||
onClick={this.props.selectMonitor}
|
||||
selected={this.props.selected || 'InspectorMonitor'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
selected: state.monitor.selected,
|
||||
});
|
||||
|
||||
const actionCreators = {
|
||||
selectMonitor,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actionCreators)(MonitorSelector);
|
|
@ -1,11 +1,32 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Container, Form } from 'devui';
|
||||
import { saveSocketSettings } from '../../actions';
|
||||
import {
|
||||
JSONSchema7,
|
||||
JSONSchema7Definition,
|
||||
JSONSchema7Type,
|
||||
JSONSchema7TypeName,
|
||||
} from 'json-schema';
|
||||
import { ConnectionType, saveSocketSettings } from '../../actions';
|
||||
import { StoreState } from '../../reducers';
|
||||
import { ConnectionOptions } from '../../reducers/connection';
|
||||
import { IChangeEvent, ISubmitEvent } from '@rjsf/core';
|
||||
|
||||
const defaultSchema = {
|
||||
declare module 'json-schema' {
|
||||
export interface JSONSchema7 {
|
||||
enumNames?: JSONSchema7Type[];
|
||||
}
|
||||
}
|
||||
|
||||
interface Schema {
|
||||
type: JSONSchema7TypeName;
|
||||
required?: string[];
|
||||
properties: {
|
||||
[key: string]: JSONSchema7Definition;
|
||||
};
|
||||
}
|
||||
|
||||
const defaultSchema: Schema = {
|
||||
type: 'object',
|
||||
required: [],
|
||||
properties: {
|
||||
|
@ -37,37 +58,24 @@ const uiSchema = {
|
|||
},
|
||||
};
|
||||
|
||||
class Connection extends Component {
|
||||
static propTypes = {
|
||||
saveSettings: PropTypes.func.isRequired,
|
||||
options: PropTypes.object.isRequired,
|
||||
type: PropTypes.string,
|
||||
};
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = this.setFormData(props.type);
|
||||
}
|
||||
interface FormData extends ConnectionOptions {
|
||||
readonly type: ConnectionType;
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
return this.state !== nextState;
|
||||
}
|
||||
interface State {
|
||||
readonly formData: FormData;
|
||||
readonly type: ConnectionType;
|
||||
readonly schema: Schema;
|
||||
readonly changed: boolean | undefined;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (this.props.options !== nextProps.options) {
|
||||
this.setState({
|
||||
formData: { ...nextProps.options, type: nextProps.type },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleSave = (data) => {
|
||||
this.props.saveSettings(data.formData);
|
||||
this.setState({ changed: false });
|
||||
};
|
||||
|
||||
setFormData = (type, changed) => {
|
||||
let schema;
|
||||
export class Connection extends Component<Props, State> {
|
||||
setFormData = (type: ConnectionType, changed?: boolean) => {
|
||||
let schema: Schema;
|
||||
if (type !== 'custom') {
|
||||
schema = {
|
||||
type: 'object',
|
||||
|
@ -87,7 +95,26 @@ class Connection extends Component {
|
|||
};
|
||||
};
|
||||
|
||||
handleChange = (data) => {
|
||||
state: State = this.setFormData(this.props.type);
|
||||
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||
return this.state !== nextState;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (this.props.options !== nextProps.options) {
|
||||
this.setState({
|
||||
formData: { ...nextProps.options, type: nextProps.type },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleSave = (data: ISubmitEvent<FormData>) => {
|
||||
this.props.saveSettings(data.formData);
|
||||
this.setState({ changed: false });
|
||||
};
|
||||
|
||||
handleChange = (data: IChangeEvent<FormData>) => {
|
||||
const formData = data.formData;
|
||||
const type = formData.type;
|
||||
if (type !== this.state.type) {
|
||||
|
@ -119,14 +146,10 @@ class Connection extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return state.connection;
|
||||
}
|
||||
const mapStateToProps = (state: StoreState) => state.connection;
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
saveSettings: bindActionCreators(saveSocketSettings, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
saveSettings: saveSocketSettings,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Connection);
|
||||
export default connect(mapStateToProps, actionCreators)(Connection);
|
|
@ -1,17 +1,15 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Container, Form } from 'devui';
|
||||
import { listSchemes, listThemes } from 'devui/lib/utils/theme';
|
||||
import { changeTheme } from '../../actions';
|
||||
import { StoreState } from '../../reducers';
|
||||
|
||||
class Themes extends Component {
|
||||
static propTypes = {
|
||||
changeTheme: PropTypes.func.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
export class Themes extends Component<Props> {
|
||||
render() {
|
||||
const theme = this.props.theme;
|
||||
const formData = {
|
||||
|
@ -49,16 +47,12 @@ class Themes extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
theme: state.theme,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
changeTheme: bindActionCreators(changeTheme, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
changeTheme,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Themes);
|
||||
export default connect(mapStateToProps, actionCreators)(Themes);
|
|
@ -1,32 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Tabs } from 'devui';
|
||||
import Connection from './Connection';
|
||||
import Themes from './Themes';
|
||||
|
||||
class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.tabs = [
|
||||
{ name: 'Connection', component: Connection },
|
||||
{ name: 'Themes', component: Themes },
|
||||
];
|
||||
this.state = { selected: 'Connection' };
|
||||
}
|
||||
|
||||
handleSelect = (selected) => {
|
||||
this.setState({ selected });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Tabs
|
||||
toRight
|
||||
tabs={this.tabs}
|
||||
selected={this.state.selected}
|
||||
onClick={this.handleSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Settings;
|
|
@ -0,0 +1,34 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Tabs } from 'devui';
|
||||
import Connection from './Connection';
|
||||
import Themes from './Themes';
|
||||
|
||||
interface State {
|
||||
selected: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
class Settings extends Component<{}, State> {
|
||||
tabs = [
|
||||
{ name: 'Connection', component: Connection },
|
||||
{ name: 'Themes', component: Themes },
|
||||
];
|
||||
state: State = { selected: 'Connection' };
|
||||
|
||||
handleSelect = (selected: string) => {
|
||||
this.setState({ selected });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
<Tabs<{}>
|
||||
tabs={this.tabs as any}
|
||||
selected={this.state.selected}
|
||||
onClick={this.handleSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Settings;
|
|
@ -1,16 +1,25 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ActionCreators } from 'redux-devtools-instrument';
|
||||
import { ActionCreators, LiftedAction } from 'redux-devtools-instrument';
|
||||
import { Button, Toolbar, Divider } from 'devui';
|
||||
import { Action } from 'redux';
|
||||
import RecordButton from './buttons/RecordButton';
|
||||
import PersistButton from './buttons/PersistButton';
|
||||
import LockButton from './buttons/LockButton';
|
||||
import InstanceSelector from './InstanceSelector';
|
||||
import SyncButton from './buttons/SyncButton';
|
||||
import { Options, State } from '../reducers/instances';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const { reset, rollback, commit, sweep } = ActionCreators;
|
||||
|
||||
export default class TopButtons extends Component {
|
||||
interface Props {
|
||||
dispatch: (action: LiftedAction<unknown, Action<unknown>, unknown>) => void;
|
||||
liftedState: State;
|
||||
options: Options;
|
||||
}
|
||||
|
||||
export default class TopButtons extends Component<Props> {
|
||||
static propTypes = {
|
||||
// shouldSync: PropTypes.bool,
|
||||
liftedState: PropTypes.object.isRequired,
|
||||
|
@ -18,7 +27,7 @@ export default class TopButtons extends Component {
|
|||
options: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return (
|
||||
nextProps.options !== this.props.options ||
|
||||
nextProps.liftedState !== this.props.liftedState
|
|
@ -1,18 +1,17 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { FaTerminal } from 'react-icons/fa';
|
||||
import { toggleDispatcher } from '../../actions';
|
||||
|
||||
class DispatcherButton extends Component {
|
||||
static propTypes = {
|
||||
dispatcherIsOpen: PropTypes.bool,
|
||||
toggleDispatcher: PropTypes.func.isRequired,
|
||||
};
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
interface OwnProps {
|
||||
dispatcherIsOpen: boolean;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
class DispatcherButton extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen;
|
||||
}
|
||||
|
||||
|
@ -32,10 +31,8 @@ class DispatcherButton extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
toggleDispatcher: bindActionCreators(toggleDispatcher, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
toggleDispatcher,
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(DispatcherButton);
|
||||
export default connect(null, actionCreators)(DispatcherButton);
|
|
@ -1,33 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { TiDownload } from 'react-icons/ti';
|
||||
import { exportState } from '../../actions';
|
||||
|
||||
class ExportButton extends Component {
|
||||
static propTypes = {
|
||||
exportState: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button title="Export to a file" onClick={this.props.exportState}>
|
||||
<TiDownload />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
exportState: bindActionCreators(exportState, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ExportButton);
|
|
@ -0,0 +1,28 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { TiDownload } from 'react-icons/ti';
|
||||
import { exportState } from '../../actions';
|
||||
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = DispatchProps;
|
||||
|
||||
class ExportButton extends Component<Props> {
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button title="Export to a file" onClick={this.props.exportState}>
|
||||
<TiDownload />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const actionCreators = {
|
||||
exportState,
|
||||
};
|
||||
|
||||
export default connect(null, actionCreators)(ExportButton);
|
|
@ -1,64 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { TiUpload } from 'react-icons/ti';
|
||||
import { importState } from '../../actions';
|
||||
|
||||
class ImportButton extends Component {
|
||||
static propTypes = {
|
||||
importState: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.handleImport = this.handleImport.bind(this);
|
||||
this.handleImportFile = this.handleImportFile.bind(this);
|
||||
this.mapRef = this.mapRef.bind(this);
|
||||
}
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
mapRef(node) {
|
||||
this.fileInput = node;
|
||||
}
|
||||
|
||||
handleImport() {
|
||||
this.fileInput.click();
|
||||
}
|
||||
|
||||
handleImportFile(e) {
|
||||
const file = e.target.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
this.props.importState(reader.result);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
e.target.value = ''; // eslint-disable-line no-param-reassign
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button title="Import from a file" onClick={this.handleImport}>
|
||||
<TiUpload />
|
||||
<input
|
||||
type="file"
|
||||
ref={this.mapRef}
|
||||
style={{ display: 'none' }}
|
||||
onChange={this.handleImportFile}
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
importState: bindActionCreators(importState, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ImportButton);
|
|
@ -0,0 +1,54 @@
|
|||
import React, { ChangeEventHandler, Component, RefCallback } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { TiUpload } from 'react-icons/ti';
|
||||
import { importState } from '../../actions';
|
||||
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = DispatchProps;
|
||||
|
||||
class ImportButton extends Component<Props> {
|
||||
fileInput?: HTMLInputElement | null;
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
mapRef: RefCallback<HTMLInputElement> = (node) => {
|
||||
this.fileInput = node;
|
||||
};
|
||||
|
||||
handleImport = () => {
|
||||
this.fileInput!.click();
|
||||
};
|
||||
|
||||
handleImportFile: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
const file = e.target.files![0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
this.props.importState(reader.result as string);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
e.target.value = '';
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button title="Import from a file" onClick={this.handleImport}>
|
||||
<TiUpload />
|
||||
<input
|
||||
type="file"
|
||||
ref={this.mapRef}
|
||||
style={{ display: 'none' }}
|
||||
onChange={this.handleImportFile}
|
||||
/>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const actionCreators = {
|
||||
importState,
|
||||
};
|
||||
|
||||
export default connect(null, actionCreators)(ImportButton);
|
|
@ -1,18 +1,19 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { IoIosLock } from 'react-icons/io';
|
||||
import { lockChanges } from '../../actions';
|
||||
import { lockChanges, StoreAction } from '../../actions';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
class LockButton extends Component {
|
||||
static propTypes = {
|
||||
locked: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
lockChanges: PropTypes.func.isRequired,
|
||||
};
|
||||
type DispatchProps = ReturnType<typeof mapDispatchToProps>;
|
||||
interface OwnProps {
|
||||
locked: boolean | undefined;
|
||||
disabled: boolean;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
class LockButton extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.locked !== this.props.locked;
|
||||
}
|
||||
|
||||
|
@ -31,7 +32,10 @@ class LockButton extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch, ownProps) {
|
||||
function mapDispatchToProps(
|
||||
dispatch: Dispatch<StoreAction>,
|
||||
ownProps: OwnProps
|
||||
) {
|
||||
return {
|
||||
lockChanges: () => dispatch(lockChanges(!ownProps.locked)),
|
||||
};
|
|
@ -1,26 +1,26 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { FaThumbtack } from 'react-icons/fa';
|
||||
import { togglePersist } from '../../actions';
|
||||
import { StoreState } from '../../reducers';
|
||||
|
||||
class LockButton extends Component {
|
||||
static propTypes = {
|
||||
persisted: PropTypes.bool,
|
||||
disabled: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
interface OwnProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
type Props = StateProps & DispatchProps & OwnProps;
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
class LockButton extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.persisted !== this.props.persisted;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
toolbar
|
||||
tooltipPosition="bottom"
|
||||
disabled={this.props.disabled}
|
||||
mark={this.props.persisted && 'base0D'}
|
||||
|
@ -37,16 +37,12 @@ class LockButton extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
persisted: state.instances.persisted,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
onClick: bindActionCreators(togglePersist, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
onClick: togglePersist,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(LockButton);
|
||||
export default connect(mapStateToProps, actionCreators)(LockButton);
|
|
@ -7,8 +7,8 @@ export default class PrintButton extends Component {
|
|||
return false;
|
||||
}
|
||||
|
||||
handlePrint() {
|
||||
const d3svg = document.getElementById('d3svg');
|
||||
handlePrint = () => {
|
||||
const d3svg = (document.getElementById('d3svg') as unknown) as SVGGElement;
|
||||
if (!d3svg) {
|
||||
window.print();
|
||||
return;
|
||||
|
@ -17,11 +17,11 @@ export default class PrintButton extends Component {
|
|||
const initHeight = d3svg.style.height;
|
||||
const initWidth = d3svg.style.width;
|
||||
const box = d3svg.getBBox();
|
||||
d3svg.style.height = box.height;
|
||||
d3svg.style.width = box.width;
|
||||
d3svg.style.height = `${box.height}`;
|
||||
d3svg.style.width = `${box.width}`;
|
||||
|
||||
const g = d3svg.firstChild;
|
||||
const initTransform = g.getAttribute('transform');
|
||||
const g = d3svg.firstChild! as SVGGElement;
|
||||
const initTransform = g.getAttribute('transform')!;
|
||||
g.setAttribute(
|
||||
'transform',
|
||||
initTransform.replace(/.+scale\(/, 'translate(57, 10) scale(')
|
||||
|
@ -32,7 +32,7 @@ export default class PrintButton extends Component {
|
|||
d3svg.style.height = initHeight;
|
||||
d3svg.style.width = initWidth;
|
||||
g.setAttribute('transform', initTransform);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
|
@ -1,17 +1,18 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { MdFiberManualRecord } from 'react-icons/md';
|
||||
import { pauseRecording } from '../../actions';
|
||||
import { pauseRecording, StoreAction } from '../../actions';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
class RecordButton extends Component {
|
||||
static propTypes = {
|
||||
paused: PropTypes.bool,
|
||||
pauseRecording: PropTypes.func.isRequired,
|
||||
};
|
||||
type DispatchProps = ReturnType<typeof mapDispatchToProps>;
|
||||
interface OwnProps {
|
||||
paused: boolean | undefined;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
class RecordButton extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.paused !== this.props.paused;
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,10 @@ class RecordButton extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch, ownProps) {
|
||||
function mapDispatchToProps(
|
||||
dispatch: Dispatch<StoreAction>,
|
||||
ownProps: OwnProps
|
||||
) {
|
||||
return {
|
||||
pauseRecording: () => dispatch(pauseRecording(!ownProps.paused)),
|
||||
};
|
|
@ -1,18 +1,17 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { MdAvTimer } from 'react-icons/md';
|
||||
import { toggleSlider } from '../../actions';
|
||||
|
||||
class SliderButton extends Component {
|
||||
static propTypes = {
|
||||
isOpen: PropTypes.bool,
|
||||
toggleSlider: PropTypes.func.isRequired,
|
||||
};
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
interface OwnProps {
|
||||
isOpen: boolean;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
class SliderButton extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.isOpen !== this.props.isOpen;
|
||||
}
|
||||
|
||||
|
@ -30,10 +29,8 @@ class SliderButton extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
toggleSlider: bindActionCreators(toggleSlider, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
toggleSlider,
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(SliderButton);
|
||||
export default connect(null, actionCreators)(SliderButton);
|
|
@ -1,45 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { TiArrowSync } from 'react-icons/ti';
|
||||
import { toggleSync } from '../../actions';
|
||||
|
||||
class SyncButton extends Component {
|
||||
static propTypes = {
|
||||
sync: PropTypes.bool,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return nextProps.sync !== this.props.sync;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
title="Sync actions"
|
||||
tooltipPosition="bottom-left"
|
||||
onClick={this.props.onClick}
|
||||
mark={this.props.sync && 'base0B'}
|
||||
>
|
||||
<TiArrowSync />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
sync: state.instances.sync,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
onClick: bindActionCreators(toggleSync, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SyncButton);
|
|
@ -0,0 +1,39 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Button } from 'devui';
|
||||
import { TiArrowSync } from 'react-icons/ti';
|
||||
import { toggleSync } from '../../actions';
|
||||
import { StoreState } from '../../reducers';
|
||||
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
class SyncButton extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.sync !== this.props.sync;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
title="Sync actions"
|
||||
tooltipPosition="bottom-left"
|
||||
onClick={this.props.onClick}
|
||||
mark={this.props.sync && 'base0B'}
|
||||
>
|
||||
<TiArrowSync />
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
sync: state.instances.sync,
|
||||
});
|
||||
|
||||
const actionCreators = {
|
||||
onClick: toggleSync,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, actionCreators)(SyncButton);
|
|
@ -1,5 +1,14 @@
|
|||
import socketCluster from 'socketcluster-client';
|
||||
|
||||
interface States {
|
||||
CLOSED: 'closed';
|
||||
CONNECTING: 'connecting';
|
||||
OPEN: 'open';
|
||||
AUTHENTICATED: 'authenticated';
|
||||
PENDING: 'pending';
|
||||
UNAUTHENTICATED: 'unauthenticated';
|
||||
}
|
||||
|
||||
export const {
|
||||
CLOSED,
|
||||
CONNECTING,
|
||||
|
@ -7,7 +16,7 @@ export const {
|
|||
AUTHENTICATED,
|
||||
PENDING,
|
||||
UNAUTHENTICATED,
|
||||
} = socketCluster.SCClientSocket;
|
||||
} = (socketCluster.SCClientSocket as unknown) as States;
|
||||
export const CONNECT_REQUEST = 'socket/CONNECT_REQUEST';
|
||||
export const CONNECT_SUCCESS = 'socket/CONNECT_SUCCESS';
|
||||
export const CONNECT_ERROR = 'socket/CONNECT_ERROR';
|
|
@ -1,7 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Container } from 'devui';
|
||||
import SliderMonitor from './monitors/Slider';
|
||||
import { liftedDispatch as liftedDispatchAction, getReport } from '../actions';
|
||||
|
@ -10,8 +8,13 @@ import DevTools from '../containers/DevTools';
|
|||
import Dispatcher from './monitors/Dispatcher';
|
||||
import TopButtons from '../components/TopButtons';
|
||||
import BottomButtons from '../components/BottomButtons';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
class Actions extends Component {
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
class Actions extends Component<Props> {
|
||||
render() {
|
||||
const {
|
||||
monitor,
|
||||
|
@ -51,17 +54,7 @@ class Actions extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Actions.propTypes = {
|
||||
liftedDispatch: PropTypes.func.isRequired,
|
||||
liftedState: PropTypes.object.isRequired,
|
||||
monitorState: PropTypes.object,
|
||||
options: PropTypes.object.isRequired,
|
||||
monitor: PropTypes.string,
|
||||
dispatcherIsOpen: PropTypes.bool,
|
||||
sliderIsOpen: PropTypes.bool,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const mapStateToProps = (state: StoreState) => {
|
||||
const instances = state.instances;
|
||||
const id = getActiveInstance(instances);
|
||||
return {
|
||||
|
@ -73,13 +66,11 @@ function mapStateToProps(state) {
|
|||
sliderIsOpen: state.monitor.sliderIsOpen,
|
||||
reports: state.reports.data,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
liftedDispatch: bindActionCreators(liftedDispatchAction, dispatch),
|
||||
getReport: bindActionCreators(getReport, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
liftedDispatch: liftedDispatchAction,
|
||||
getReport,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Actions);
|
||||
export default connect(mapStateToProps, actionCreators)(Actions);
|
|
@ -1,14 +1,17 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Container, Notification } from 'devui';
|
||||
import { clearNotification } from '../actions';
|
||||
import Header from '../components/Header';
|
||||
import Actions from '../containers/Actions';
|
||||
import Settings from '../components/Settings';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
class App extends Component {
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps & DispatchProps;
|
||||
|
||||
class App extends Component<Props> {
|
||||
render() {
|
||||
const { section, theme, notification } = this.props;
|
||||
let body;
|
||||
|
@ -37,28 +40,14 @@ class App extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
section: PropTypes.string.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
notification: PropTypes.shape({
|
||||
message: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
}),
|
||||
clearNotification: PropTypes.func,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
section: state.section,
|
||||
theme: state.theme,
|
||||
notification: state.notification,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
clearNotification: bindActionCreators(clearNotification, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
clearNotification,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
export default connect(mapStateToProps, actionCreators)(App);
|
|
@ -1,20 +1,49 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { withTheme } from 'styled-components';
|
||||
import { LiftedAction, LiftedState } from 'redux-devtools-instrument';
|
||||
import { Action } from 'redux';
|
||||
import getMonitor from '../utils/getMonitor';
|
||||
import { InitMonitorAction } from '../actions';
|
||||
import { Features, State } from '../reducers/instances';
|
||||
import { MonitorStateMonitorState } from '../reducers/monitor';
|
||||
import { ThemeFromProvider } from 'devui';
|
||||
|
||||
class DevTools extends Component {
|
||||
constructor(props) {
|
||||
interface Props {
|
||||
monitor: string;
|
||||
liftedState: State;
|
||||
monitorState: MonitorStateMonitorState | undefined;
|
||||
dispatch: (
|
||||
action: LiftedAction<unknown, Action<unknown>, unknown> | InitMonitorAction
|
||||
) => void;
|
||||
features: Features | undefined;
|
||||
theme: ThemeFromProvider;
|
||||
}
|
||||
|
||||
class DevTools extends Component<Props> {
|
||||
monitorProps: unknown;
|
||||
Monitor?: React.ComponentType<
|
||||
LiftedState<unknown, Action<unknown>, unknown>
|
||||
> & {
|
||||
update(
|
||||
monitorProps: unknown,
|
||||
state: unknown | undefined,
|
||||
action: Action<unknown>
|
||||
): unknown;
|
||||
};
|
||||
preventRender?: boolean;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.getMonitor(props, props.monitorState);
|
||||
}
|
||||
|
||||
getMonitor(props, skipUpdate) {
|
||||
getMonitor(props: Props, skipUpdate?: unknown) {
|
||||
const monitorElement = getMonitor(props);
|
||||
this.monitorProps = monitorElement.props;
|
||||
this.Monitor = monitorElement.type;
|
||||
|
||||
const update = this.Monitor.update;
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
const update = this.Monitor!.update;
|
||||
if (update) {
|
||||
let newMonitorState;
|
||||
const monitorState = props.monitorState;
|
||||
|
@ -24,7 +53,11 @@ class DevTools extends Component {
|
|||
) {
|
||||
newMonitorState = monitorState;
|
||||
} else {
|
||||
newMonitorState = update(this.monitorProps, undefined, {});
|
||||
newMonitorState = update(
|
||||
this.monitorProps,
|
||||
undefined,
|
||||
{} as Action<unknown>
|
||||
);
|
||||
if (newMonitorState !== monitorState) {
|
||||
this.preventRender = true;
|
||||
}
|
||||
|
@ -38,21 +71,23 @@ class DevTools extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
UNSAFE_componentWillUpdate(nextProps) {
|
||||
UNSAFE_componentWillUpdate(nextProps: Props) {
|
||||
if (nextProps.monitor !== this.props.monitor) this.getMonitor(nextProps);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return (
|
||||
nextProps.monitor !== this.props.monitor ||
|
||||
nextProps.liftedState !== this.props.liftedState ||
|
||||
nextProps.monitorState !== this.props.liftedState ||
|
||||
nextProps.monitorState !== this.props.monitorState ||
|
||||
nextProps.features !== this.props.features ||
|
||||
nextProps.theme.scheme !== this.props.theme.scheme
|
||||
);
|
||||
}
|
||||
|
||||
dispatch = (action) => {
|
||||
dispatch = (
|
||||
action: LiftedAction<unknown, Action<unknown>, unknown> | InitMonitorAction
|
||||
) => {
|
||||
this.props.dispatch(action);
|
||||
};
|
||||
|
||||
|
@ -66,9 +101,10 @@ class DevTools extends Component {
|
|||
...this.props.liftedState,
|
||||
monitorState: this.props.monitorState,
|
||||
};
|
||||
const MonitorAsAny = this.Monitor as any;
|
||||
return (
|
||||
<div className={`monitor monitor-${this.props.monitor}`}>
|
||||
<this.Monitor
|
||||
<MonitorAsAny
|
||||
{...liftedState}
|
||||
{...this.monitorProps}
|
||||
features={this.props.features}
|
||||
|
@ -80,13 +116,4 @@ class DevTools extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
DevTools.propTypes = {
|
||||
liftedState: PropTypes.object,
|
||||
monitorState: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
monitor: PropTypes.string,
|
||||
features: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withTheme(DevTools);
|
|
@ -1,25 +1,27 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import ChartMonitor from 'redux-devtools-chart-monitor';
|
||||
import { NodeWithId } from 'd3-state-visualizer';
|
||||
import { selectMonitorWithState } from '../../actions';
|
||||
|
||||
export function getPath(obj, inspectedStatePath) {
|
||||
export function getPath(obj: NodeWithId, inspectedStatePath: string[]) {
|
||||
const parent = obj.parent;
|
||||
if (!parent) return;
|
||||
getPath(parent, inspectedStatePath);
|
||||
let name = obj.name;
|
||||
const item = name.match(/.+\[(\d+)]/);
|
||||
const item = /.+\[(\d+)]/.exec(name);
|
||||
if (item) name = item[1];
|
||||
inspectedStatePath.push(name);
|
||||
}
|
||||
|
||||
class ChartMonitorWrapper extends Component {
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = DispatchProps;
|
||||
|
||||
class ChartMonitorWrapper extends Component<Props> {
|
||||
static update = ChartMonitor.update;
|
||||
|
||||
onClickText = (data) => {
|
||||
const inspectedStatePath = [];
|
||||
onClickText = (data: NodeWithId) => {
|
||||
const inspectedStatePath: string[] = [];
|
||||
getPath(data, inspectedStatePath);
|
||||
this.props.selectMonitorWithState('InspectorMonitor', {
|
||||
inspectedStatePath,
|
||||
|
@ -33,6 +35,8 @@ class ChartMonitorWrapper extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
<ChartMonitor
|
||||
defaultIsVisible
|
||||
invertTheme
|
||||
|
@ -43,17 +47,8 @@ class ChartMonitorWrapper extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
ChartMonitorWrapper.propTypes = {
|
||||
selectMonitorWithState: PropTypes.func.isRequired,
|
||||
const actionCreators = {
|
||||
selectMonitorWithState: selectMonitorWithState,
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
selectMonitorWithState: bindActionCreators(
|
||||
selectMonitorWithState,
|
||||
dispatch
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ChartMonitorWrapper);
|
||||
export default connect(null, actionCreators)(ChartMonitorWrapper);
|
|
@ -1,12 +1,11 @@
|
|||
// Based on https://github.com/YoruNoHikage/redux-devtools-dispatch
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { Button, Select, Editor, Toolbar } from 'devui';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { dispatchRemotely } from '../../actions';
|
||||
import { Options } from '../../reducers/instances';
|
||||
|
||||
export const DispatcherContainer = styled.div`
|
||||
display: flex;
|
||||
|
@ -47,13 +46,22 @@ export const ActionContainer = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
class Dispatcher extends Component {
|
||||
static propTypes = {
|
||||
options: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
interface OwnProps {
|
||||
options: Options;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
state = {
|
||||
interface State {
|
||||
selected: 'default' | number;
|
||||
customAction: string;
|
||||
args: (string | undefined)[];
|
||||
rest: string;
|
||||
changed: boolean;
|
||||
}
|
||||
|
||||
class Dispatcher extends Component<Props, State> {
|
||||
state: State = {
|
||||
selected: 'default',
|
||||
customAction:
|
||||
this.props.options.lib === 'redux' ? "{\n type: ''\n}" : 'this.',
|
||||
|
@ -62,7 +70,7 @@ class Dispatcher extends Component {
|
|||
changed: false,
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (
|
||||
this.state.selected !== 'default' &&
|
||||
!nextProps.options.actionCreators
|
||||
|
@ -74,14 +82,14 @@ class Dispatcher extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||
return (
|
||||
nextState !== this.state ||
|
||||
nextProps.options.actionCreators !== this.props.options.actionCreators
|
||||
);
|
||||
}
|
||||
|
||||
selectActionCreator = (selected) => {
|
||||
selectActionCreator = (selected: 'default' | 'actions-help' | number) => {
|
||||
if (selected === 'actions-help') {
|
||||
window.open(
|
||||
'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/' +
|
||||
|
@ -90,14 +98,14 @@ class Dispatcher extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const args = [];
|
||||
const args: string[] = [];
|
||||
if (selected !== 'default') {
|
||||
args.length = this.props.options.actionCreators[selected].args.length;
|
||||
args.length = this.props.options.actionCreators![selected].args.length;
|
||||
}
|
||||
this.setState({ selected, args, rest: '[]', changed: false });
|
||||
};
|
||||
|
||||
handleArg = (argIndex) => (value) => {
|
||||
handleArg = (argIndex: number) => (value: string) => {
|
||||
const args = [
|
||||
...this.state.args.slice(0, argIndex),
|
||||
value || undefined,
|
||||
|
@ -106,26 +114,26 @@ class Dispatcher extends Component {
|
|||
this.setState({ args, changed: true });
|
||||
};
|
||||
|
||||
handleRest = (rest) => {
|
||||
handleRest = (rest: string) => {
|
||||
this.setState({ rest, changed: true });
|
||||
};
|
||||
|
||||
handleCustomAction = (customAction) => {
|
||||
handleCustomAction = (customAction: string) => {
|
||||
this.setState({ customAction, changed: true });
|
||||
};
|
||||
|
||||
dispatchAction = () => {
|
||||
const { selected, customAction, args, rest } = this.state;
|
||||
|
||||
if (this.state.selected !== 'default') {
|
||||
if (selected !== 'default') {
|
||||
// remove trailing `undefined` arguments
|
||||
let i = args.length - 1;
|
||||
while (i >= 0 && typeof args[i] === 'undefined') {
|
||||
args.pop(i);
|
||||
args.pop();
|
||||
i--;
|
||||
}
|
||||
this.props.dispatch({
|
||||
name: this.props.options.actionCreators[selected].name,
|
||||
name: this.props.options.actionCreators![selected].name,
|
||||
selected,
|
||||
args,
|
||||
rest,
|
||||
|
@ -174,7 +182,9 @@ class Dispatcher extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
let options = [{ value: 'default', label: 'Custom action' }];
|
||||
let options: { value: string | number; label: string }[] = [
|
||||
{ value: 'default', label: 'Custom action' },
|
||||
];
|
||||
if (actionCreators && actionCreators.length > 0) {
|
||||
options = options.concat(
|
||||
actionCreators.map(({ name, args }, i) => ({
|
||||
|
@ -208,10 +218,8 @@ class Dispatcher extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
dispatch: bindActionCreators(dispatchRemotely, dispatch),
|
||||
};
|
||||
}
|
||||
const actionCreators = {
|
||||
dispatch: dispatchRemotely,
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(Dispatcher);
|
||||
export default connect(null, actionCreators)(Dispatcher);
|
|
@ -1,18 +1,28 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import React, { Component, RefCallback } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { withTheme } from 'styled-components';
|
||||
import { tree } from 'd3-state-visualizer';
|
||||
import { InputOptions, NodeWithId, tree } from 'd3-state-visualizer';
|
||||
import { getPath } from '../ChartMonitorWrapper';
|
||||
import { updateMonitorState } from '../../../actions';
|
||||
import { ThemeFromProvider } from 'devui';
|
||||
|
||||
const style = {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
class ChartTab extends Component {
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
interface OwnProps {
|
||||
data: unknown;
|
||||
theme: ThemeFromProvider;
|
||||
}
|
||||
type Props = DispatchProps & OwnProps;
|
||||
|
||||
class ChartTab extends Component<Props> {
|
||||
node?: HTMLDivElement | null;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
renderChart?: (nextState?: {} | null | undefined) => void;
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
@ -21,28 +31,30 @@ class ChartTab extends Component {
|
|||
this.createChart(this.props);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (
|
||||
this.props.theme.scheme !== nextProps.theme.scheme ||
|
||||
nextProps.theme.light !== this.props.theme.light
|
||||
) {
|
||||
this.node.innerHTML = '';
|
||||
this.node!.innerHTML = '';
|
||||
this.createChart(nextProps);
|
||||
} else if (nextProps.data !== this.props.data) {
|
||||
this.renderChart(nextProps.data);
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
this.renderChart!(nextProps.data as {} | null | undefined);
|
||||
}
|
||||
}
|
||||
|
||||
getRef = (node) => {
|
||||
getRef: RefCallback<HTMLDivElement> = (node) => {
|
||||
this.node = node;
|
||||
};
|
||||
|
||||
createChart(props) {
|
||||
this.renderChart = tree(this.node, this.getChartTheme(props.theme));
|
||||
this.renderChart(props.data);
|
||||
createChart(props: Props) {
|
||||
this.renderChart = tree(this.node!, this.getChartTheme(props.theme));
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
this.renderChart(props.data as {} | null | undefined);
|
||||
}
|
||||
|
||||
getChartTheme(theme) {
|
||||
getChartTheme(theme: ThemeFromProvider): Partial<InputOptions> {
|
||||
return {
|
||||
heightBetweenNodesCoeff: 1,
|
||||
widthBetweenNodesCoeff: 1.3,
|
||||
|
@ -60,27 +72,27 @@ class ChartTab extends Component {
|
|||
style: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
node: {
|
||||
node: ({
|
||||
colors: {
|
||||
default: theme.base0B,
|
||||
collapsed: theme.base0B,
|
||||
parent: theme.base0E,
|
||||
},
|
||||
radius: 7,
|
||||
},
|
||||
text: {
|
||||
} as unknown) as string,
|
||||
text: ({
|
||||
colors: {
|
||||
default: theme.base0D,
|
||||
hover: theme.base06,
|
||||
},
|
||||
},
|
||||
} as unknown) as string,
|
||||
},
|
||||
onClickText: this.onClickText,
|
||||
};
|
||||
}
|
||||
|
||||
onClickText = (data) => {
|
||||
const inspectedStatePath = [];
|
||||
onClickText = (data: NodeWithId) => {
|
||||
const inspectedStatePath: string[] = [];
|
||||
getPath(data, inspectedStatePath);
|
||||
this.props.updateMonitorState({
|
||||
inspectedStatePath,
|
||||
|
@ -93,17 +105,9 @@ class ChartTab extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
ChartTab.propTypes = {
|
||||
data: PropTypes.object,
|
||||
updateMonitorState: PropTypes.func.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
const actionCreators = {
|
||||
updateMonitorState,
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
updateMonitorState: bindActionCreators(updateMonitorState, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
const ConnectedChartTab = connect(null, mapDispatchToProps)(ChartTab);
|
||||
const ConnectedChartTab = connect(null, actionCreators)(ChartTab);
|
||||
export default withTheme(ConnectedChartTab);
|
|
@ -2,21 +2,27 @@ import React, { Component } from 'react';
|
|||
import { Editor } from 'devui';
|
||||
import { stringify } from 'javascript-stringify';
|
||||
|
||||
export default class RawTab extends Component {
|
||||
constructor(props) {
|
||||
interface Props {
|
||||
data: unknown;
|
||||
}
|
||||
|
||||
export default class RawTab extends Component<Props> {
|
||||
value?: string | undefined;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.stringifyData(props);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return nextProps.data !== this.value;
|
||||
}
|
||||
|
||||
UNSAFE_componentWillUpdate(nextProps) {
|
||||
UNSAFE_componentWillUpdate(nextProps: Props) {
|
||||
this.stringifyData(nextProps);
|
||||
}
|
||||
|
||||
stringifyData(props) {
|
||||
stringifyData(props: Props) {
|
||||
this.value = stringify(props.data, null, 2);
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Tabs } from 'devui';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { Tab, Tabs } from 'devui';
|
||||
import { TabComponentProps } from 'redux-devtools-inspector-monitor';
|
||||
import { Action } from 'redux';
|
||||
import StateTree from 'redux-devtools-inspector-monitor/lib/tabs/StateTab';
|
||||
import ActionTree from 'redux-devtools-inspector-monitor/lib/tabs/ActionTab';
|
||||
import DiffTree from 'redux-devtools-inspector-monitor/lib/tabs/DiffTab';
|
||||
|
@ -10,14 +10,24 @@ import { selectMonitorTab } from '../../../actions';
|
|||
import RawTab from './RawTab';
|
||||
import ChartTab from './ChartTab';
|
||||
import VisualDiffTab from './VisualDiffTab';
|
||||
import { StoreState } from '../../../reducers';
|
||||
import { Delta } from 'jsondiffpatch';
|
||||
|
||||
class SubTabs extends Component {
|
||||
constructor(props) {
|
||||
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||
type Props = StateProps &
|
||||
DispatchProps &
|
||||
TabComponentProps<unknown, Action<unknown>>;
|
||||
|
||||
class SubTabs extends Component<Props> {
|
||||
tabs?: (Tab<Props> | Tab<{ data: unknown }> | Tab<{ data?: Delta }>)[];
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.updateTabs(props);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (nextProps.parentTab !== this.props.parentTab) {
|
||||
this.updateTabs(nextProps);
|
||||
}
|
||||
|
@ -34,7 +44,7 @@ class SubTabs extends Component {
|
|||
}
|
||||
};
|
||||
|
||||
updateTabs(props) {
|
||||
updateTabs(props: Props) {
|
||||
const parentTab = props.parentTab;
|
||||
|
||||
if (parentTab === 'Diff') {
|
||||
|
@ -47,7 +57,7 @@ class SubTabs extends Component {
|
|||
{
|
||||
name: 'Raw',
|
||||
component: VisualDiffTab,
|
||||
selector: this.selector,
|
||||
selector: this.selector as () => { data?: Delta },
|
||||
},
|
||||
];
|
||||
return;
|
||||
|
@ -79,7 +89,7 @@ class SubTabs extends Component {
|
|||
|
||||
return (
|
||||
<Tabs
|
||||
tabs={this.tabs}
|
||||
tabs={this.tabs! as any}
|
||||
selected={selected || 'Tree'}
|
||||
onClick={this.props.selectMonitorTab}
|
||||
/>
|
||||
|
@ -87,26 +97,13 @@ class SubTabs extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
SubTabs.propTypes = {
|
||||
selected: PropTypes.string,
|
||||
parentTab: PropTypes.string,
|
||||
selectMonitorTab: PropTypes.func.isRequired,
|
||||
action: PropTypes.object,
|
||||
delta: PropTypes.object,
|
||||
nextState: PropTypes.object,
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
parentTab: state.monitor.monitorState!.tabName,
|
||||
selected: state.monitor.monitorState!.subTabName,
|
||||
});
|
||||
|
||||
const actionCreators = {
|
||||
selectMonitorTab,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
parentTab: state.monitor.monitorState.tabName,
|
||||
selected: state.monitor.monitorState.subTabName,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
selectMonitorTab: bindActionCreators(selectMonitorTab, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SubTabs);
|
||||
export default connect(mapStateToProps, actionCreators)(SubTabs);
|
|
@ -1,6 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { formatters } from 'jsondiffpatch';
|
||||
import { Delta, formatters } from 'jsondiffpatch';
|
||||
import styled from 'styled-components';
|
||||
import { effects } from 'devui';
|
||||
|
||||
|
@ -218,22 +217,22 @@ export const StyledContainer = styled.div`
|
|||
}
|
||||
`;
|
||||
|
||||
export default class VisualDiffTab extends Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
interface Props {
|
||||
data?: Delta;
|
||||
}
|
||||
|
||||
export default class VisualDiffTab extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return this.props.data !== nextProps.data;
|
||||
}
|
||||
|
||||
render() {
|
||||
let __html;
|
||||
let __html: string | undefined;
|
||||
const data = this.props.data;
|
||||
if (data) {
|
||||
__html = formatters.html.format(data);
|
||||
__html = formatters.html.format(data, undefined);
|
||||
}
|
||||
|
||||
return <StyledContainer dangerouslySetInnerHTML={{ __html }} />;
|
||||
return <StyledContainer dangerouslySetInnerHTML={{ __html: __html! }} />;
|
||||
}
|
||||
}
|
||||
|
||||
VisualDiffTab.propTypes = {
|
||||
data: PropTypes.object,
|
||||
};
|
|
@ -1,10 +1,10 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import InspectorMonitor from 'redux-devtools-inspector-monitor';
|
||||
import InspectorMonitor, { Tab } from 'redux-devtools-inspector-monitor';
|
||||
import TraceTab from 'redux-devtools-inspector-monitor-trace-tab';
|
||||
import TestTab from 'redux-devtools-inspector-monitor-test-tab';
|
||||
import { DATA_TYPE_KEY } from '../../../constants/dataTypes';
|
||||
import SubTabs from './SubTabs';
|
||||
import { Action } from 'redux';
|
||||
|
||||
const DEFAULT_TABS = [
|
||||
{
|
||||
|
@ -25,25 +25,38 @@ const DEFAULT_TABS = [
|
|||
},
|
||||
];
|
||||
|
||||
class InspectorWrapper extends Component {
|
||||
interface Features {
|
||||
test?: boolean;
|
||||
skip?: boolean;
|
||||
}
|
||||
interface Props {
|
||||
features?: Features;
|
||||
}
|
||||
|
||||
class InspectorWrapper extends Component<Props> {
|
||||
static update = InspectorMonitor.update;
|
||||
|
||||
render() {
|
||||
const { features, ...rest } = this.props;
|
||||
let tabs;
|
||||
let tabs: () => Tab<unknown, Action<unknown>>[];
|
||||
if (features && features.test) {
|
||||
tabs = () => [...DEFAULT_TABS, { name: 'Test', component: TestTab }];
|
||||
tabs = () => [
|
||||
...(DEFAULT_TABS as Tab<unknown, Action<unknown>>[]),
|
||||
({ name: 'Test', component: TestTab } as unknown) as Tab<
|
||||
unknown,
|
||||
Action<unknown>
|
||||
>,
|
||||
];
|
||||
} else {
|
||||
tabs = () => DEFAULT_TABS;
|
||||
tabs = () => DEFAULT_TABS as Tab<unknown, Action<unknown>>[];
|
||||
}
|
||||
|
||||
return (
|
||||
<InspectorMonitor
|
||||
dataTypeKey={DATA_TYPE_KEY}
|
||||
shouldPersistState={false}
|
||||
invertTheme={false}
|
||||
tabs={tabs}
|
||||
hideActionButtons={!features.skip}
|
||||
hideActionButtons={!features!.skip}
|
||||
hideMainButtons
|
||||
{...rest}
|
||||
/>
|
||||
|
@ -51,8 +64,4 @@ class InspectorWrapper extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
InspectorWrapper.propTypes = {
|
||||
features: PropTypes.object,
|
||||
};
|
||||
|
||||
export default InspectorWrapper;
|
|
@ -1,7 +1,10 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled, { withTheme } from 'styled-components';
|
||||
import SliderMonitor from 'redux-devtools-slider-monitor';
|
||||
import { LiftedAction } from 'redux-devtools-instrument';
|
||||
import { Action } from 'redux';
|
||||
import { ThemeFromProvider } from 'devui';
|
||||
import { State } from '../../reducers/instances';
|
||||
|
||||
const SliderWrapper = styled.div`
|
||||
border-color: ${(props) => props.theme.base02};
|
||||
|
@ -9,8 +12,14 @@ const SliderWrapper = styled.div`
|
|||
border-width: 1px 0;
|
||||
`;
|
||||
|
||||
class Slider extends Component {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
interface Props {
|
||||
liftedState: State;
|
||||
dispatch: (action: LiftedAction<unknown, Action<unknown>, unknown>) => void;
|
||||
theme: ThemeFromProvider;
|
||||
}
|
||||
|
||||
class Slider extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return (
|
||||
nextProps.liftedState !== this.props.liftedState ||
|
||||
nextProps.theme.scheme !== this.props.theme.scheme
|
||||
|
@ -21,6 +30,8 @@ class Slider extends Component {
|
|||
<SliderWrapper>
|
||||
<SliderMonitor
|
||||
{...this.props.liftedState}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
dispatch={this.props.dispatch}
|
||||
theme={this.props.theme}
|
||||
hideResetButton
|
||||
|
@ -30,10 +41,4 @@ class Slider extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Slider.propTypes = {
|
||||
liftedState: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withTheme(Slider);
|
|
@ -1,18 +1,27 @@
|
|||
import 'devui/lib/presets';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Provider } from 'react-redux';
|
||||
import { Store } from 'redux';
|
||||
import configureStore from './store/configureStore';
|
||||
import { CONNECT_REQUEST } from './constants/socketActionTypes';
|
||||
import App from './containers/App';
|
||||
import { StoreState } from './reducers';
|
||||
import { ConnectionOptions, StoreAction } from './actions';
|
||||
|
||||
interface Props {
|
||||
socketOptions?: ConnectionOptions;
|
||||
}
|
||||
|
||||
class Root extends Component<Props> {
|
||||
store?: Store<StoreState, StoreAction>;
|
||||
|
||||
class Root extends Component {
|
||||
UNSAFE_componentWillMount() {
|
||||
configureStore((store, preloadedState) => {
|
||||
this.store = store;
|
||||
store.dispatch({
|
||||
type: CONNECT_REQUEST,
|
||||
options: preloadedState.connection || this.props.socketOptions,
|
||||
options: (preloadedState!.connection ||
|
||||
this.props.socketOptions) as ConnectionOptions,
|
||||
});
|
||||
this.forceUpdate();
|
||||
});
|
||||
|
@ -20,21 +29,13 @@ class Root extends Component {
|
|||
|
||||
render() {
|
||||
if (!this.store) return null;
|
||||
const AppAsAny = App as any;
|
||||
return (
|
||||
<Provider store={this.store}>
|
||||
<App {...this.props} />
|
||||
<AppAsAny {...this.props} />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Root.propTypes = {
|
||||
socketOptions: PropTypes.shape({
|
||||
hostname: PropTypes.string,
|
||||
port: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
autoReconnect: PropTypes.bool,
|
||||
secure: PropTypes.bool,
|
||||
}),
|
||||
};
|
||||
|
||||
export default Root;
|
|
@ -1,5 +1,6 @@
|
|||
import socketCluster from 'socketcluster-client';
|
||||
import socketCluster, { SCClientSocket } from 'socketcluster-client';
|
||||
import { stringify } from 'jsan';
|
||||
import { Dispatch, MiddlewareAPI } from 'redux';
|
||||
import socketOptions from '../constants/socketOptions';
|
||||
import * as actions from '../constants/socketActionTypes';
|
||||
import { getActiveInstance } from '../reducers/instances';
|
||||
|
@ -12,22 +13,37 @@ import {
|
|||
GET_REPORT_ERROR,
|
||||
GET_REPORT_SUCCESS,
|
||||
} from '../constants/actionTypes';
|
||||
import { showNotification, importState } from '../actions';
|
||||
import {
|
||||
showNotification,
|
||||
importState,
|
||||
StoreAction,
|
||||
EmitAction,
|
||||
LiftedActionAction,
|
||||
Request,
|
||||
DispatchAction,
|
||||
UpdateReportsRequest,
|
||||
} from '../actions';
|
||||
import { nonReduxDispatch } from '../utils/monitorActions';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
let socket;
|
||||
let store;
|
||||
let socket: SCClientSocket;
|
||||
let store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>;
|
||||
|
||||
function emit({ message: type, id, instanceId, action, state }) {
|
||||
function emit({ message: type, id, instanceId, action, state }: EmitAction) {
|
||||
socket.emit(id ? 'sc-' + id : 'respond', { type, action, state, instanceId });
|
||||
}
|
||||
|
||||
function startMonitoring(channel) {
|
||||
function startMonitoring(channel: string) {
|
||||
if (channel !== store.getState().socket.baseChannel) return;
|
||||
store.dispatch({ type: actions.EMIT, message: 'START' });
|
||||
}
|
||||
|
||||
function dispatchRemoteAction({ message, action, state, toAll }) {
|
||||
function dispatchRemoteAction({
|
||||
message,
|
||||
action,
|
||||
state,
|
||||
toAll,
|
||||
}: LiftedActionAction) {
|
||||
const instances = store.getState().instances;
|
||||
const instanceId = getActiveInstance(instances);
|
||||
const id = !toAll && instances.options[instanceId].connectionId;
|
||||
|
@ -39,7 +55,7 @@ function dispatchRemoteAction({ message, action, state, toAll }) {
|
|||
store,
|
||||
message,
|
||||
instanceId,
|
||||
action,
|
||||
action as DispatchAction,
|
||||
state,
|
||||
instances
|
||||
),
|
||||
|
@ -48,7 +64,32 @@ function dispatchRemoteAction({ message, action, state, toAll }) {
|
|||
});
|
||||
}
|
||||
|
||||
function monitoring(request) {
|
||||
interface RequestBase {
|
||||
id?: string;
|
||||
instanceId?: string;
|
||||
}
|
||||
interface DisconnectedAction extends RequestBase {
|
||||
type: 'DISCONNECTED';
|
||||
id: string;
|
||||
}
|
||||
interface StartAction extends RequestBase {
|
||||
type: 'START';
|
||||
id: string;
|
||||
}
|
||||
interface ErrorAction extends RequestBase {
|
||||
type: 'ERROR';
|
||||
payload: string;
|
||||
}
|
||||
interface RequestWithData extends RequestBase {
|
||||
data: Request;
|
||||
}
|
||||
type MonitoringRequest =
|
||||
| DisconnectedAction
|
||||
| StartAction
|
||||
| ErrorAction
|
||||
| Request;
|
||||
|
||||
function monitoring(request: MonitoringRequest) {
|
||||
if (request.type === 'DISCONNECTED') {
|
||||
store.dispatch({
|
||||
type: REMOVE_INSTANCE,
|
||||
|
@ -68,7 +109,9 @@ function monitoring(request) {
|
|||
|
||||
store.dispatch({
|
||||
type: UPDATE_STATE,
|
||||
request: request.data ? { ...request.data, id: request.id } : request,
|
||||
request: ((request as unknown) as RequestWithData).data
|
||||
? { ...((request as unknown) as RequestWithData).data, id: request.id }
|
||||
: request,
|
||||
});
|
||||
|
||||
const instances = store.getState().instances;
|
||||
|
@ -87,11 +130,14 @@ function monitoring(request) {
|
|||
}
|
||||
}
|
||||
|
||||
function subscribe(channelName, subscription) {
|
||||
function subscribe(
|
||||
channelName: string,
|
||||
subscription: typeof UPDATE_STATE | typeof UPDATE_REPORTS
|
||||
) {
|
||||
const channel = socket.subscribe(channelName);
|
||||
if (subscription === UPDATE_STATE) channel.watch(monitoring);
|
||||
else {
|
||||
const watcher = (request) => {
|
||||
const watcher = (request: UpdateReportsRequest) => {
|
||||
store.dispatch({ type: subscription, request });
|
||||
};
|
||||
channel.watch(watcher);
|
||||
|
@ -150,7 +196,7 @@ function connect() {
|
|||
socket = socketCluster.create(
|
||||
connection.type === 'remotedev' ? socketOptions : connection.options
|
||||
);
|
||||
handleConnection(store);
|
||||
handleConnection();
|
||||
} catch (error) {
|
||||
store.dispatch({ type: actions.CONNECT_ERROR, error });
|
||||
store.dispatch(showNotification(error.message || error));
|
||||
|
@ -163,7 +209,7 @@ function disconnect() {
|
|||
}
|
||||
|
||||
function login() {
|
||||
socket.emit('login', {}, (error, baseChannel) => {
|
||||
socket.emit('login', {}, (error: Error, baseChannel: string) => {
|
||||
if (error) {
|
||||
store.dispatch({ type: actions.AUTH_ERROR, error });
|
||||
return;
|
||||
|
@ -182,24 +228,28 @@ function login() {
|
|||
});
|
||||
}
|
||||
|
||||
function getReport(reportId) {
|
||||
socket.emit('getReport', reportId, (error, data) => {
|
||||
function getReport(reportId: unknown) {
|
||||
socket.emit(
|
||||
'getReport',
|
||||
reportId,
|
||||
(error: Error, data: { payload: string }) => {
|
||||
if (error) {
|
||||
store.dispatch({ type: GET_REPORT_ERROR, error });
|
||||
return;
|
||||
}
|
||||
store.dispatch({ type: GET_REPORT_SUCCESS, data });
|
||||
store.dispatch(importState(data.payload));
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default function api(inStore) {
|
||||
export default function api(
|
||||
inStore: MiddlewareAPI<Dispatch<StoreAction>, StoreState>
|
||||
) {
|
||||
store = inStore;
|
||||
return (next) => (action) => {
|
||||
return (next: Dispatch<StoreAction>) => (action: StoreAction) => {
|
||||
const result = next(action);
|
||||
switch (
|
||||
action.type // eslint-disable-line default-case
|
||||
) {
|
||||
switch (action.type) {
|
||||
case actions.CONNECT_REQUEST:
|
||||
connect();
|
||||
break;
|
|
@ -1,14 +1,17 @@
|
|||
import stringifyJSON from '../utils/stringifyJSON';
|
||||
import { UPDATE_STATE, LIFTED_ACTION, EXPORT } from '../constants/actionTypes';
|
||||
import { getActiveInstance } from '../reducers/instances';
|
||||
import { Dispatch, MiddlewareAPI } from 'redux';
|
||||
import { ExportRequest, StoreAction } from '../actions';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
let toExport;
|
||||
let toExport: string | undefined;
|
||||
|
||||
function download(state) {
|
||||
function download(state: string) {
|
||||
const blob = new Blob([state], { type: 'octet/stream' });
|
||||
const href = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.style = 'display: none';
|
||||
a.style.display = 'none';
|
||||
a.download = 'state.json';
|
||||
a.href = href;
|
||||
document.body.appendChild(a);
|
||||
|
@ -19,15 +22,17 @@ function download(state) {
|
|||
}, 0);
|
||||
}
|
||||
|
||||
const exportState = (store) => (next) => (action) => {
|
||||
const exportState = (
|
||||
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>
|
||||
) => (next: Dispatch<StoreAction>) => (action: StoreAction) => {
|
||||
const result = next(action);
|
||||
|
||||
if (
|
||||
toExport &&
|
||||
action.type === UPDATE_STATE &&
|
||||
action.request.type === 'EXPORT'
|
||||
action.request!.type === 'EXPORT'
|
||||
) {
|
||||
const request = action.request;
|
||||
const request = action.request!;
|
||||
const id = request.instanceId || request.id;
|
||||
if (id === toExport) {
|
||||
toExport = undefined;
|
||||
|
@ -35,7 +40,7 @@ const exportState = (store) => (next) => (action) => {
|
|||
JSON.stringify(
|
||||
{
|
||||
payload: request.payload,
|
||||
preloadedState: request.committedState,
|
||||
preloadedState: (request as ExportRequest).committedState,
|
||||
},
|
||||
null,
|
||||
'\t'
|
|
@ -1,11 +1,22 @@
|
|||
import { RECONNECT } from '../constants/socketActionTypes';
|
||||
import { ConnectionType, StoreAction } from '../actions';
|
||||
|
||||
export interface ConnectionOptions {
|
||||
readonly hostname: string;
|
||||
readonly port: number;
|
||||
readonly secure: boolean;
|
||||
}
|
||||
export interface ConnectionState {
|
||||
readonly options: ConnectionOptions;
|
||||
readonly type: ConnectionType;
|
||||
}
|
||||
|
||||
export default function connection(
|
||||
state = {
|
||||
state: ConnectionState = {
|
||||
options: { hostname: 'localhost', port: 8000, secure: false },
|
||||
type: 'remotedev',
|
||||
},
|
||||
action
|
||||
action: StoreAction
|
||||
) {
|
||||
if (action.type === RECONNECT) {
|
||||
const { type, ...options } = action.options;
|
|
@ -1,22 +0,0 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import section from './section';
|
||||
import connection from './connection';
|
||||
import socket from './socket';
|
||||
import monitor from './monitor';
|
||||
import notification from './notification';
|
||||
import instances from './instances';
|
||||
import reports from './reports';
|
||||
import theme from './theme';
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
section,
|
||||
theme,
|
||||
connection,
|
||||
socket,
|
||||
monitor,
|
||||
instances,
|
||||
reports,
|
||||
notification,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
34
packages/redux-devtools-core/src/app/reducers/index.ts
Normal file
34
packages/redux-devtools-core/src/app/reducers/index.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { combineReducers } from 'redux';
|
||||
import section, { SectionState } from './section';
|
||||
import connection, { ConnectionState } from './connection';
|
||||
import socket, { SocketState } from './socket';
|
||||
import monitor, { MonitorState } from './monitor';
|
||||
import notification, { NotificationState } from './notification';
|
||||
import instances, { InstancesState } from './instances';
|
||||
import reports, { ReportsState } from './reports';
|
||||
import theme, { ThemeState } from './theme';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
export interface StoreState {
|
||||
readonly section: SectionState;
|
||||
readonly theme: ThemeState;
|
||||
readonly connection: ConnectionState;
|
||||
readonly socket: SocketState;
|
||||
readonly monitor: MonitorState;
|
||||
readonly instances: InstancesState;
|
||||
readonly reports: ReportsState;
|
||||
readonly notification: NotificationState;
|
||||
}
|
||||
|
||||
const rootReducer = combineReducers<StoreState, StoreAction>({
|
||||
section,
|
||||
theme,
|
||||
connection,
|
||||
socket,
|
||||
monitor,
|
||||
instances,
|
||||
reports,
|
||||
notification,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
|
@ -1,3 +1,5 @@
|
|||
import { PerformAction } from 'redux-devtools-instrument';
|
||||
import { Action } from 'redux';
|
||||
import {
|
||||
UPDATE_STATE,
|
||||
SET_STATE,
|
||||
|
@ -10,8 +12,60 @@ import {
|
|||
import { DISCONNECTED } from '../constants/socketActionTypes';
|
||||
import parseJSON from '../utils/parseJSON';
|
||||
import { recompute } from '../utils/updateState';
|
||||
import {
|
||||
ActionCreator,
|
||||
LiftedActionDispatchAction,
|
||||
Request,
|
||||
StoreAction,
|
||||
} from '../actions';
|
||||
|
||||
export const initialState = {
|
||||
export interface Features {
|
||||
lock?: boolean;
|
||||
export?: string | boolean;
|
||||
import?: string | boolean;
|
||||
persist?: boolean;
|
||||
pause?: boolean;
|
||||
reorder?: boolean;
|
||||
jump?: boolean;
|
||||
skip?: boolean;
|
||||
dispatch?: boolean;
|
||||
sync?: boolean;
|
||||
test?: boolean;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
name?: string;
|
||||
connectionId?: string;
|
||||
explicitLib?: string;
|
||||
lib?: string;
|
||||
actionCreators?: ActionCreator[];
|
||||
features: Features;
|
||||
serialize?: boolean;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
actionsById: { [actionId: number]: PerformAction<Action<unknown>> };
|
||||
computedStates: { state: unknown; error?: string }[];
|
||||
currentStateIndex: number;
|
||||
nextActionId: number;
|
||||
skippedActionIds: number[];
|
||||
stagedActionIds: number[];
|
||||
committedState?: unknown;
|
||||
isLocked?: boolean;
|
||||
isPaused?: boolean;
|
||||
}
|
||||
|
||||
export interface InstancesState {
|
||||
selected: string | null;
|
||||
current: string;
|
||||
sync: boolean;
|
||||
connections: { [id: string]: string[] };
|
||||
options: { [id: string]: Options };
|
||||
states: { [id: string]: State };
|
||||
persisted?: boolean;
|
||||
}
|
||||
|
||||
export const initialState: InstancesState = {
|
||||
selected: null,
|
||||
current: 'default',
|
||||
sync: false,
|
||||
|
@ -29,35 +83,42 @@ export const initialState = {
|
|||
},
|
||||
};
|
||||
|
||||
function updateState(state, request, id, serialize) {
|
||||
let payload = request.payload;
|
||||
function updateState(
|
||||
state: { [id: string]: State },
|
||||
request: Request,
|
||||
id: string,
|
||||
serialize: boolean | undefined
|
||||
) {
|
||||
let payload: State = request.payload as State;
|
||||
const actionsById = request.actionsById;
|
||||
if (actionsById) {
|
||||
payload = {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
...payload,
|
||||
actionsById: parseJSON(actionsById, serialize),
|
||||
computedStates: parseJSON(request.computedStates, serialize),
|
||||
};
|
||||
} as State;
|
||||
if (request.type === 'STATE' && request.committedState) {
|
||||
payload.committedState = payload.computedStates[0].state;
|
||||
}
|
||||
} else {
|
||||
payload = parseJSON(payload, serialize);
|
||||
payload = parseJSON((payload as unknown) as string, serialize) as State;
|
||||
}
|
||||
|
||||
let newState;
|
||||
const liftedState = state[id] || state.default;
|
||||
const action = (request.action && parseJSON(request.action, serialize)) || {};
|
||||
const action = ((request.action && parseJSON(request.action, serialize)) ||
|
||||
{}) as PerformAction<Action<unknown>>;
|
||||
|
||||
switch (request.type) {
|
||||
case 'INIT':
|
||||
newState = recompute(state.default, payload, {
|
||||
action: { type: '@@INIT' },
|
||||
timestamp: action.timestamp || Date.now(),
|
||||
timestamp: (action as { timestamp?: number }).timestamp || Date.now(),
|
||||
});
|
||||
break;
|
||||
case 'ACTION': {
|
||||
let isExcess = request.isExcess;
|
||||
const isExcess = request.isExcess;
|
||||
const nextActionId = request.nextActionId || liftedState.nextActionId + 1;
|
||||
const maxAge = request.maxAge;
|
||||
if (Array.isArray(action)) {
|
||||
|
@ -66,7 +127,7 @@ function updateState(state, request, id, serialize) {
|
|||
for (let i = 0; i < action.length; i++) {
|
||||
newState = recompute(
|
||||
newState,
|
||||
request.batched ? payload : payload[i],
|
||||
request.batched ? payload : ((payload as unknown) as State[])[i],
|
||||
action[i],
|
||||
newState.nextActionId + 1,
|
||||
maxAge,
|
||||
|
@ -148,7 +209,10 @@ function updateState(state, request, id, serialize) {
|
|||
return { ...state, [id]: newState };
|
||||
}
|
||||
|
||||
export function dispatchAction(state, { action }) {
|
||||
export function dispatchAction(
|
||||
state: InstancesState,
|
||||
{ action }: LiftedActionDispatchAction
|
||||
) {
|
||||
if (action.type === 'JUMP_TO_STATE' || action.type === 'JUMP_TO_ACTION') {
|
||||
const id = state.selected || state.current;
|
||||
const liftedState = state.states[id];
|
||||
|
@ -167,7 +231,7 @@ export function dispatchAction(state, { action }) {
|
|||
return state;
|
||||
}
|
||||
|
||||
function removeState(state, connectionId) {
|
||||
function removeState(state: InstancesState, connectionId: string) {
|
||||
const instanceIds = state.connections[connectionId];
|
||||
if (!instanceIds) return state;
|
||||
|
||||
|
@ -202,7 +266,11 @@ function removeState(state, connectionId) {
|
|||
};
|
||||
}
|
||||
|
||||
function init({ type, action, name, libConfig = {} }, connectionId, current) {
|
||||
function init(
|
||||
{ type, action, name, libConfig = {} }: Request,
|
||||
connectionId: string,
|
||||
current: string
|
||||
): Options {
|
||||
let lib;
|
||||
let actionCreators;
|
||||
let creators = libConfig.actionCreators || action;
|
||||
|
@ -234,7 +302,10 @@ function init({ type, action, name, libConfig = {} }, connectionId, current) {
|
|||
};
|
||||
}
|
||||
|
||||
export default function instances(state = initialState, action) {
|
||||
export default function instances(
|
||||
state = initialState,
|
||||
action: StoreAction
|
||||
): InstancesState {
|
||||
switch (action.type) {
|
||||
case UPDATE_STATE: {
|
||||
const { request } = action;
|
||||
|
@ -293,7 +364,7 @@ export default function instances(state = initialState, action) {
|
|||
...state,
|
||||
states: {
|
||||
...state.states,
|
||||
[id]: parseJSON(action.state),
|
||||
[id]: parseJSON(action.state) as State,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -307,7 +378,5 @@ export default function instances(state = initialState, action) {
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-disable no-shadow */
|
||||
export const getActiveInstance = (instances) =>
|
||||
export const getActiveInstance = (instances: InstancesState) =>
|
||||
instances.selected || instances.current;
|
||||
/* eslint-enable */
|
|
@ -5,28 +5,50 @@ import {
|
|||
TOGGLE_SLIDER,
|
||||
TOGGLE_DISPATCHER,
|
||||
} from '../constants/actionTypes';
|
||||
import { MonitorActionAction, StoreAction } from '../actions';
|
||||
|
||||
const initialState = {
|
||||
export interface MonitorStateMonitorState {
|
||||
inspectedStatePath?: string[];
|
||||
tabName?: string;
|
||||
subTabName?: string;
|
||||
selectedActionId?: number | null;
|
||||
startActionId?: number | null;
|
||||
inspectedActionPath?: string[];
|
||||
__overwritten__?: string;
|
||||
}
|
||||
export interface MonitorState {
|
||||
selected: string;
|
||||
monitorState: MonitorStateMonitorState | undefined;
|
||||
sliderIsOpen: boolean;
|
||||
dispatcherIsOpen: boolean;
|
||||
}
|
||||
|
||||
const initialState: MonitorState = {
|
||||
selected: 'InspectorMonitor',
|
||||
monitorState: undefined,
|
||||
sliderIsOpen: true,
|
||||
dispatcherIsOpen: false,
|
||||
};
|
||||
|
||||
export function dispatchMonitorAction(state, action) {
|
||||
export function dispatchMonitorAction(
|
||||
state: MonitorState,
|
||||
action: MonitorActionAction
|
||||
): MonitorState {
|
||||
return {
|
||||
...state,
|
||||
monitorState:
|
||||
action.action.newMonitorState ||
|
||||
monitorState: (action.action.newMonitorState ||
|
||||
action.monitorReducer(
|
||||
action.monitorProps,
|
||||
state.monitorState,
|
||||
action.action
|
||||
),
|
||||
)) as MonitorStateMonitorState,
|
||||
};
|
||||
}
|
||||
|
||||
export default function monitor(state = initialState, action) {
|
||||
export default function monitor(
|
||||
state = initialState,
|
||||
action: StoreAction
|
||||
): MonitorState {
|
||||
switch (action.type) {
|
||||
case MONITOR_ACTION:
|
||||
return dispatchMonitorAction(state, action);
|
||||
|
@ -45,7 +67,7 @@ export default function monitor(state = initialState, action) {
|
|||
};
|
||||
}
|
||||
case UPDATE_MONITOR_STATE: {
|
||||
let inspectedStatePath = state.monitorState.inspectedStatePath;
|
||||
let inspectedStatePath = state.monitorState!.inspectedStatePath!;
|
||||
if (action.nextState.inspectedStatePath) {
|
||||
inspectedStatePath = [
|
||||
...inspectedStatePath.slice(0, -1),
|
|
@ -4,8 +4,18 @@ import {
|
|||
LIFTED_ACTION,
|
||||
ERROR,
|
||||
} from '../constants/actionTypes';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
export default function notification(state = null, action) {
|
||||
interface Notification {
|
||||
readonly type: 'error';
|
||||
readonly message: string;
|
||||
}
|
||||
export type NotificationState = Notification | null;
|
||||
|
||||
export default function notification(
|
||||
state: NotificationState = null,
|
||||
action: StoreAction
|
||||
): NotificationState {
|
||||
switch (action.type) {
|
||||
case SHOW_NOTIFICATION:
|
||||
return action.notification;
|
|
@ -1,12 +1,24 @@
|
|||
import {
|
||||
UPDATE_REPORTS /* , GET_REPORT_SUCCESS */,
|
||||
} from '../constants/actionTypes';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
const initialState = {
|
||||
export interface Data {
|
||||
id: unknown;
|
||||
}
|
||||
|
||||
export interface ReportsState {
|
||||
data: Data[];
|
||||
}
|
||||
|
||||
const initialState: ReportsState = {
|
||||
data: [],
|
||||
};
|
||||
|
||||
export default function reports(state = initialState, action) {
|
||||
export default function reports(
|
||||
state = initialState,
|
||||
action: StoreAction
|
||||
): ReportsState {
|
||||
/* if (action.type === GET_REPORT_SUCCESS) {
|
||||
const id = action.data.id;
|
||||
return {
|
||||
|
@ -19,17 +31,16 @@ export default function reports(state = initialState, action) {
|
|||
return state;
|
||||
|
||||
const request = action.request;
|
||||
const data = request.data;
|
||||
switch (request.type) {
|
||||
case 'list':
|
||||
return {
|
||||
...state,
|
||||
data,
|
||||
data: request.data,
|
||||
};
|
||||
case 'add':
|
||||
return {
|
||||
...state,
|
||||
data: [...state.data, data],
|
||||
data: [...state.data, request.data],
|
||||
};
|
||||
case 'remove':
|
||||
return {
|
|
@ -1,8 +0,0 @@
|
|||
import { CHANGE_SECTION } from '../constants/actionTypes';
|
||||
|
||||
export default function section(state = 'Actions', action) {
|
||||
if (action.type === CHANGE_SECTION) {
|
||||
return action.section;
|
||||
}
|
||||
return state;
|
||||
}
|
11
packages/redux-devtools-core/src/app/reducers/section.ts
Normal file
11
packages/redux-devtools-core/src/app/reducers/section.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { CHANGE_SECTION } from '../constants/actionTypes';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
export type SectionState = string;
|
||||
|
||||
export default function section(state = 'Actions', action: StoreAction) {
|
||||
if (action.type === CHANGE_SECTION) {
|
||||
return action.section;
|
||||
}
|
||||
return state;
|
||||
}
|
|
@ -1,15 +1,29 @@
|
|||
import { AuthStates, States } from 'socketcluster-client/lib/scclientsocket';
|
||||
import * as actions from '../constants/socketActionTypes';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
const initialState = {
|
||||
export interface SocketState {
|
||||
id: string | null;
|
||||
channels: string[];
|
||||
socketState: States;
|
||||
authState: AuthStates | 'pending';
|
||||
error: Error | undefined;
|
||||
baseChannel?: string;
|
||||
authToken?: null;
|
||||
}
|
||||
|
||||
const initialState: SocketState = {
|
||||
id: null,
|
||||
channels: [],
|
||||
socketState: actions.CLOSED,
|
||||
authState: actions.PENDING,
|
||||
authToken: null,
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
export default function socket(state = initialState, action) {
|
||||
export default function socket(
|
||||
state = initialState,
|
||||
action: StoreAction
|
||||
): SocketState {
|
||||
switch (action.type) {
|
||||
case actions.CONNECT_REQUEST: {
|
||||
return {
|
||||
|
@ -39,7 +53,6 @@ export default function socket(state = initialState, action) {
|
|||
return {
|
||||
...state,
|
||||
authState: actions.AUTHENTICATED,
|
||||
authToken: action.authToken,
|
||||
baseChannel: action.baseChannel,
|
||||
};
|
||||
case actions.AUTH_ERROR:
|
||||
|
@ -57,13 +70,13 @@ export default function socket(state = initialState, action) {
|
|||
case actions.SUBSCRIBE_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
channels: [...state.channels, action.channelName],
|
||||
channels: [...state.channels, action.channel],
|
||||
};
|
||||
case actions.UNSUBSCRIBE:
|
||||
return {
|
||||
...state,
|
||||
channels: state.channels.filter(
|
||||
(channel) => channel !== action.channelName
|
||||
(channel) => channel !== action.channel
|
||||
),
|
||||
};
|
||||
case actions.DISCONNECTED:
|
|
@ -1,15 +0,0 @@
|
|||
import { CHANGE_THEME } from '../constants/actionTypes';
|
||||
|
||||
export default function theme(
|
||||
state = { theme: 'default', scheme: 'default', light: true },
|
||||
action
|
||||
) {
|
||||
if (action.type === CHANGE_THEME) {
|
||||
return {
|
||||
theme: action.theme,
|
||||
scheme: action.scheme,
|
||||
light: !action.dark,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
27
packages/redux-devtools-core/src/app/reducers/theme.ts
Normal file
27
packages/redux-devtools-core/src/app/reducers/theme.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
import { Scheme, Theme } from 'devui';
|
||||
import { CHANGE_THEME } from '../constants/actionTypes';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
export interface ThemeState {
|
||||
readonly theme: Theme;
|
||||
readonly scheme: Scheme;
|
||||
readonly light: boolean;
|
||||
}
|
||||
|
||||
export default function theme(
|
||||
state: ThemeState = {
|
||||
theme: 'default' as const,
|
||||
scheme: 'default' as const,
|
||||
light: true,
|
||||
},
|
||||
action: StoreAction
|
||||
) {
|
||||
if (action.type === CHANGE_THEME) {
|
||||
return {
|
||||
theme: action.theme,
|
||||
scheme: action.scheme,
|
||||
light: !action.dark,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import { createStore, compose, applyMiddleware } from 'redux';
|
||||
import localForage from 'localforage';
|
||||
import { getStoredState, createPersistor } from 'redux-persist';
|
||||
import api from '../middlewares/api';
|
||||
import exportState from '../middlewares/exportState';
|
||||
import rootReducer from '../reducers';
|
||||
|
||||
export default function configureStore(callback, key) {
|
||||
const persistConfig = {
|
||||
keyPrefix: `redux-devtools${key || ''}:`,
|
||||
blacklist: ['instances', 'socket'],
|
||||
storage: localForage,
|
||||
serialize: (data) => data,
|
||||
deserialize: (data) => data,
|
||||
};
|
||||
|
||||
getStoredState(persistConfig, (err, restoredState) => {
|
||||
let composeEnhancers = compose;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
|
||||
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||
}
|
||||
if (module.hot) {
|
||||
// Enable Webpack hot module replacement for reducers
|
||||
module.hot.accept('../reducers', () => {
|
||||
const nextReducer = require('../reducers'); // eslint-disable-line global-require
|
||||
store.replaceReducer(nextReducer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
restoredState,
|
||||
composeEnhancers(applyMiddleware(exportState, api))
|
||||
);
|
||||
const persistor = createPersistor(store, persistConfig);
|
||||
callback(store, restoredState);
|
||||
if (err) persistor.purge();
|
||||
});
|
||||
}
|
60
packages/redux-devtools-core/src/app/store/configureStore.ts
Normal file
60
packages/redux-devtools-core/src/app/store/configureStore.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { createStore, compose, applyMiddleware, Store } from 'redux';
|
||||
import localForage from 'localforage';
|
||||
import {
|
||||
getStoredState,
|
||||
createPersistor,
|
||||
PersistorConfig,
|
||||
} from 'redux-persist';
|
||||
import api from '../middlewares/api';
|
||||
import exportState from '../middlewares/exportState';
|
||||
import rootReducer, { StoreState } from '../reducers';
|
||||
import { StoreAction } from '../actions';
|
||||
|
||||
export default function configureStore(
|
||||
callback: (
|
||||
store: Store<StoreState, StoreAction>,
|
||||
restoredState: Partial<StoreState> | undefined
|
||||
) => void,
|
||||
key?: string
|
||||
) {
|
||||
const persistConfig: PersistorConfig = ({
|
||||
keyPrefix: `redux-devtools${key || ''}:`,
|
||||
blacklist: ['instances', 'socket'],
|
||||
storage: localForage,
|
||||
serialize: (data: unknown) => data,
|
||||
deserialize: (data: unknown) => data,
|
||||
} as unknown) as PersistorConfig;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
getStoredState<StoreState>(persistConfig, (err, restoredState) => {
|
||||
let composeEnhancers = compose;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (
|
||||
((window as unknown) as {
|
||||
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
|
||||
}).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||
) {
|
||||
composeEnhancers = ((window as unknown) as {
|
||||
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: typeof compose;
|
||||
}).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
|
||||
}
|
||||
if (module.hot) {
|
||||
// Enable Webpack hot module replacement for reducers
|
||||
module.hot.accept('../reducers', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const nextReducer = require('../reducers'); // eslint-disable-line global-require
|
||||
store.replaceReducer(nextReducer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
restoredState,
|
||||
composeEnhancers(applyMiddleware(exportState, api))
|
||||
);
|
||||
const persistor = createPersistor(store, persistConfig);
|
||||
callback(store, restoredState);
|
||||
if (err) persistor.purge();
|
||||
});
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
// Based on https://github.com/gaearon/redux-devtools/pull/241
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
export default function commitExcessActions(liftedState, n = 1) {
|
||||
import { State } from '../reducers/instances';
|
||||
|
||||
export default function commitExcessActions(liftedState: State, n = 1) {
|
||||
// Auto-commits n-number of excess actions.
|
||||
let excess = n;
|
||||
let idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1);
|
|
@ -9,7 +9,7 @@ export const monitors = [
|
|||
{ value: 'ChartMonitor', name: 'Chart' },
|
||||
];
|
||||
|
||||
export default function getMonitor({ monitor }) {
|
||||
export default function getMonitor({ monitor }: { monitor: string }) {
|
||||
switch (monitor) {
|
||||
case 'LogMonitor':
|
||||
return (
|
|
@ -2,8 +2,12 @@ import difference from 'lodash/difference';
|
|||
import omit from 'lodash/omit';
|
||||
import stringifyJSON from './stringifyJSON';
|
||||
import { SET_STATE } from '../constants/actionTypes';
|
||||
import { InstancesState, State } from '../reducers/instances';
|
||||
import { Dispatch, MiddlewareAPI } from 'redux';
|
||||
import { DispatchAction, StoreAction } from '../actions';
|
||||
import { StoreState } from '../reducers';
|
||||
|
||||
export function sweep(state) {
|
||||
export function sweep(state: State): State {
|
||||
return {
|
||||
...state,
|
||||
actionsById: omit(state.actionsById, state.skippedActionIds),
|
||||
|
@ -17,12 +21,12 @@ export function sweep(state) {
|
|||
}
|
||||
|
||||
export function nonReduxDispatch(
|
||||
store,
|
||||
message,
|
||||
instanceId,
|
||||
action,
|
||||
initialState,
|
||||
preInstances
|
||||
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
|
||||
message: string,
|
||||
instanceId: string,
|
||||
action: DispatchAction,
|
||||
initialState: string | undefined,
|
||||
preInstances: InstancesState
|
||||
) {
|
||||
const instances = preInstances || store.getState().instances;
|
||||
const state = instances.states[instanceId];
|
|
@ -1,17 +1,17 @@
|
|||
import jsan from 'jsan';
|
||||
import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes';
|
||||
|
||||
export function reviver(key, value) {
|
||||
export function reviver(key: string, value: unknown) {
|
||||
if (
|
||||
typeof value === 'object' &&
|
||||
value !== null &&
|
||||
'__serializedType__' in value &&
|
||||
typeof value.data === 'object'
|
||||
typeof (value as any).data === 'object'
|
||||
) {
|
||||
const data = value.data;
|
||||
data[DATA_TYPE_KEY] = value.__serializedType__;
|
||||
const data = (value as any).data;
|
||||
data[DATA_TYPE_KEY] = (value as any).__serializedType__;
|
||||
if ('__serializedRef__' in value)
|
||||
data[DATA_REF_KEY] = value.__serializedRef__;
|
||||
data[DATA_REF_KEY] = (value as any).__serializedRef__;
|
||||
/*
|
||||
if (Array.isArray(data)) {
|
||||
data.__serializedType__ = value.__serializedType__;
|
||||
|
@ -26,7 +26,10 @@ export function reviver(key, value) {
|
|||
return value;
|
||||
}
|
||||
|
||||
export default function parseJSON(data, serialize) {
|
||||
export default function parseJSON(
|
||||
data: string | undefined,
|
||||
serialize?: boolean
|
||||
) {
|
||||
if (typeof data !== 'string') return data;
|
||||
try {
|
||||
return serialize ? jsan.parse(data, reviver) : jsan.parse(data);
|
|
@ -1,20 +0,0 @@
|
|||
import jsan from 'jsan';
|
||||
import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes';
|
||||
|
||||
function replacer(key, value) {
|
||||
if (typeof value === 'object' && value !== null && DATA_TYPE_KEY in value) {
|
||||
const __serializedType__ = value[DATA_TYPE_KEY];
|
||||
const clone = { ...value };
|
||||
delete clone[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign
|
||||
const r = { data: clone, __serializedType__ };
|
||||
if (DATA_REF_KEY in value) r.__serializedRef__ = clone[DATA_REF_KEY];
|
||||
return r;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export default function stringifyJSON(data, serialize) {
|
||||
return serialize
|
||||
? jsan.stringify(data, replacer, null, true)
|
||||
: jsan.stringify(data);
|
||||
}
|
24
packages/redux-devtools-core/src/app/utils/stringifyJSON.ts
Normal file
24
packages/redux-devtools-core/src/app/utils/stringifyJSON.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import jsan from 'jsan';
|
||||
import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes';
|
||||
|
||||
function replacer(key: string, value: unknown) {
|
||||
if (typeof value === 'object' && value !== null && DATA_TYPE_KEY in value) {
|
||||
const __serializedType__ = (value as any)[DATA_TYPE_KEY];
|
||||
const clone = { ...value };
|
||||
delete (clone as any)[DATA_TYPE_KEY]; // eslint-disable-line no-param-reassign
|
||||
const r = { data: clone, __serializedType__ };
|
||||
if (DATA_REF_KEY in value)
|
||||
(r as any).__serializedRef__ = (clone as any)[DATA_REF_KEY];
|
||||
return r;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export default function stringifyJSON(
|
||||
data: unknown,
|
||||
serialize: boolean | undefined
|
||||
) {
|
||||
return serialize
|
||||
? jsan.stringify(data, replacer, (null as unknown) as undefined, true)
|
||||
: jsan.stringify(data);
|
||||
}
|
|
@ -1,12 +1,17 @@
|
|||
import commitExcessActions from './commitExcessActions';
|
||||
import { State } from '../reducers/instances';
|
||||
import { Action } from 'redux';
|
||||
import { PerformAction } from 'redux-devtools-instrument';
|
||||
|
||||
export function recompute(
|
||||
previousLiftedState,
|
||||
storeState,
|
||||
action,
|
||||
previousLiftedState: State,
|
||||
storeState: State,
|
||||
action:
|
||||
| PerformAction<Action<unknown>>
|
||||
| { action: Action<unknown>; timestamp?: number; stack?: string },
|
||||
nextActionId = 1,
|
||||
maxAge,
|
||||
isExcess
|
||||
maxAge?: number,
|
||||
isExcess?: boolean
|
||||
) {
|
||||
const actionId = nextActionId - 1;
|
||||
const liftedState = { ...previousLiftedState };
|
||||
|
@ -19,8 +24,10 @@ export function recompute(
|
|||
}
|
||||
liftedState.stagedActionIds = [...liftedState.stagedActionIds, actionId];
|
||||
liftedState.actionsById = { ...liftedState.actionsById };
|
||||
if (action.type === 'PERFORM_ACTION') {
|
||||
liftedState.actionsById[actionId] = action;
|
||||
if ((action as PerformAction<Action<unknown>>).type === 'PERFORM_ACTION') {
|
||||
liftedState.actionsById[actionId] = action as PerformAction<
|
||||
Action<unknown>
|
||||
>;
|
||||
} else {
|
||||
liftedState.actionsById[actionId] = {
|
||||
action: action.action || action,
|
|
@ -1,8 +0,0 @@
|
|||
function injectedScript() {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.error(
|
||||
"Not implemented yet. WIP. If you're looking for utils, import `redux-devtools-core/lib/utils`."
|
||||
);
|
||||
}
|
||||
|
||||
export default injectedScript;
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import App from './src/app';
|
||||
import App from './app';
|
||||
|
||||
render(<App />, document.getElementById('root'));
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
const ERROR = '@@redux-devtools/ERROR';
|
||||
|
||||
export default function catchErrors(sendError) {
|
||||
if (typeof window === 'object' && typeof window.onerror === 'object') {
|
||||
window.onerror = function (message, url, lineNo, columnNo, error) {
|
||||
const errorAction = { type: ERROR, message, url, lineNo, columnNo };
|
||||
if (error && error.stack) errorAction.stack = error.stack;
|
||||
sendError(errorAction);
|
||||
return false;
|
||||
};
|
||||
} else if (typeof global !== 'undefined' && global.ErrorUtils) {
|
||||
global.ErrorUtils.setGlobalHandler((error, isFatal) => {
|
||||
sendError({ type: ERROR, error, isFatal });
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-disable no-console */
|
||||
if (
|
||||
typeof console === 'object' &&
|
||||
typeof console.error === 'function' &&
|
||||
!console.beforeRemotedev
|
||||
) {
|
||||
console.beforeRemotedev = console.error.bind(console);
|
||||
console.error = function () {
|
||||
let errorAction = { type: ERROR };
|
||||
const error = arguments[0];
|
||||
errorAction.message = error.message ? error.message : error;
|
||||
if (error.sourceURL) {
|
||||
errorAction = {
|
||||
...errorAction,
|
||||
sourceURL: error.sourceURL,
|
||||
line: error.line,
|
||||
column: error.column,
|
||||
};
|
||||
}
|
||||
if (error.stack) errorAction.stack = error.stack;
|
||||
sendError(errorAction);
|
||||
console.beforeRemotedev.apply(null, arguments);
|
||||
};
|
||||
}
|
||||
/* eslint-enable no-console */
|
||||
}
|
68
packages/redux-devtools-core/src/utils/catchErrors.ts
Normal file
68
packages/redux-devtools-core/src/utils/catchErrors.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
const ERROR = '@@redux-devtools/ERROR';
|
||||
|
||||
interface ErrorAction {
|
||||
type: typeof ERROR;
|
||||
message?: Event | string;
|
||||
url?: string | undefined;
|
||||
lineNo?: number | undefined;
|
||||
columnNo?: number | undefined;
|
||||
stack?: string;
|
||||
error?: Error;
|
||||
isFatal?: boolean;
|
||||
sourceURL?: string;
|
||||
line?: number;
|
||||
column?: number;
|
||||
}
|
||||
|
||||
export default function catchErrors(
|
||||
sendError: (errorAction: ErrorAction) => void
|
||||
) {
|
||||
if (typeof window === 'object' && typeof window.onerror === 'object') {
|
||||
window.onerror = function (message, url, lineNo, columnNo, error) {
|
||||
const errorAction: ErrorAction = {
|
||||
type: ERROR,
|
||||
message,
|
||||
url,
|
||||
lineNo,
|
||||
columnNo,
|
||||
};
|
||||
if (error && error.stack) errorAction.stack = error.stack;
|
||||
sendError(errorAction);
|
||||
return false;
|
||||
};
|
||||
} else if (typeof global !== 'undefined' && (global as any).ErrorUtils) {
|
||||
(global as any).ErrorUtils.setGlobalHandler(
|
||||
(error: Error, isFatal: boolean) => {
|
||||
sendError({ type: ERROR, error, isFatal });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/* eslint-disable no-console */
|
||||
if (
|
||||
typeof console === 'object' &&
|
||||
typeof console.error === 'function' &&
|
||||
!(console as any).beforeRemotedev
|
||||
) {
|
||||
(console as any).beforeRemotedev = console.error.bind(console);
|
||||
console.error = function () {
|
||||
let errorAction: ErrorAction = { type: ERROR };
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
const error = arguments[0];
|
||||
errorAction.message = error.message ? error.message : error;
|
||||
if (error.sourceURL) {
|
||||
errorAction = {
|
||||
...errorAction,
|
||||
sourceURL: error.sourceURL,
|
||||
line: error.line,
|
||||
column: error.column,
|
||||
};
|
||||
}
|
||||
if (error.stack) errorAction.stack = error.stack;
|
||||
sendError(errorAction);
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
(console as any).beforeRemotedev.apply(null, arguments);
|
||||
};
|
||||
}
|
||||
/* eslint-enable no-console */
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
import mapValues from 'lodash/mapValues';
|
||||
import { PerformAction } from 'redux-devtools-instrument';
|
||||
import { Action } from 'redux';
|
||||
import { State } from '../app/reducers/instances';
|
||||
|
||||
export const FilterState = {
|
||||
DO_NOT_FILTER: 'DO_NOT_FILTER',
|
||||
|
@ -6,19 +9,25 @@ export const FilterState = {
|
|||
WHITELIST_SPECIFIC: 'WHITELIST_SPECIFIC',
|
||||
};
|
||||
|
||||
export function arrToRegex(v) {
|
||||
export function arrToRegex(v: string | string[]) {
|
||||
return typeof v === 'string' ? v : v.join('|');
|
||||
}
|
||||
|
||||
function filterActions(actionsById, actionsFilter) {
|
||||
function filterActions(
|
||||
actionsById: { [actionId: number]: PerformAction<Action<unknown>> },
|
||||
actionsFilter: (action: Action<unknown>, id: number) => Action
|
||||
) {
|
||||
if (!actionsFilter) return actionsById;
|
||||
return mapValues(actionsById, (action, id) => ({
|
||||
return mapValues(actionsById, (action, id: number) => ({
|
||||
...action,
|
||||
action: actionsFilter(action.action, id),
|
||||
}));
|
||||
}
|
||||
|
||||
function filterStates(computedStates, statesFilter) {
|
||||
function filterStates(
|
||||
computedStates: { state: unknown; error?: string | undefined }[],
|
||||
statesFilter: (state: unknown, actionId: number) => unknown
|
||||
) {
|
||||
if (!statesFilter) return computedStates;
|
||||
return computedStates.map((state, idx) => ({
|
||||
...state,
|
||||
|
@ -26,7 +35,17 @@ function filterStates(computedStates, statesFilter) {
|
|||
}));
|
||||
}
|
||||
|
||||
export function getLocalFilter(config) {
|
||||
interface Config {
|
||||
actionsBlacklist?: string[];
|
||||
actionsWhitelist?: string[];
|
||||
}
|
||||
|
||||
interface LocalFilter {
|
||||
whitelist?: string;
|
||||
blacklist?: string;
|
||||
}
|
||||
|
||||
export function getLocalFilter(config: Config): LocalFilter | undefined {
|
||||
if (config.actionsBlacklist || config.actionsWhitelist) {
|
||||
return {
|
||||
whitelist: config.actionsWhitelist && config.actionsWhitelist.join('|'),
|
||||
|
@ -36,33 +55,53 @@ export function getLocalFilter(config) {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
interface DevToolsOptions {
|
||||
filter?:
|
||||
| typeof FilterState.DO_NOT_FILTER
|
||||
| typeof FilterState.BLACKLIST_SPECIFIC
|
||||
| typeof FilterState.WHITELIST_SPECIFIC;
|
||||
whitelist?: string;
|
||||
blacklist?: string;
|
||||
}
|
||||
function getDevToolsOptions() {
|
||||
return (typeof window !== 'undefined' && window.devToolsOptions) || {};
|
||||
return (
|
||||
(typeof window !== 'undefined' &&
|
||||
(window as { devToolsOptions?: DevToolsOptions }).devToolsOptions) ||
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
export function isFiltered(action, localFilter) {
|
||||
const { type } = action.action || action;
|
||||
export function isFiltered(
|
||||
action: PerformAction<Action<unknown>> | Action<unknown>,
|
||||
localFilter?: LocalFilter
|
||||
) {
|
||||
const { type } = (action as PerformAction<Action<unknown>>).action || action;
|
||||
const opts = getDevToolsOptions();
|
||||
if (
|
||||
(!localFilter &&
|
||||
opts.filter &&
|
||||
opts.filter === FilterState.DO_NOT_FILTER) ||
|
||||
(type && typeof type.match !== 'function')
|
||||
(type && typeof (type as string).match !== 'function')
|
||||
)
|
||||
return false;
|
||||
|
||||
const { whitelist, blacklist } = localFilter || opts;
|
||||
return (
|
||||
(whitelist && !type.match(whitelist)) ||
|
||||
(blacklist && type.match(blacklist))
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
|
||||
(whitelist && !(type as string).match(whitelist)) ||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
|
||||
(blacklist && (type as string).match(blacklist))
|
||||
);
|
||||
}
|
||||
|
||||
export function filterStagedActions(state, filters) {
|
||||
export function filterStagedActions(state: State, filters: LocalFilter) {
|
||||
if (!filters) return state;
|
||||
|
||||
const filteredStagedActionIds = [];
|
||||
const filteredComputedStates = [];
|
||||
const filteredStagedActionIds: number[] = [];
|
||||
const filteredComputedStates: {
|
||||
state: unknown;
|
||||
error?: string | undefined;
|
||||
}[] = [];
|
||||
|
||||
state.stagedActionIds.forEach((id, idx) => {
|
||||
if (!isFiltered(state.actionsById[id], filters)) {
|
||||
|
@ -79,13 +118,13 @@ export function filterStagedActions(state, filters) {
|
|||
}
|
||||
|
||||
export function filterState(
|
||||
state,
|
||||
type,
|
||||
localFilter,
|
||||
stateSanitizer,
|
||||
actionSanitizer,
|
||||
nextActionId,
|
||||
predicate
|
||||
state: State,
|
||||
type: string,
|
||||
localFilter: LocalFilter,
|
||||
stateSanitizer: (state: unknown, actionId: number) => unknown,
|
||||
actionSanitizer: (action: Action<unknown>, id: number) => Action,
|
||||
nextActionId: number,
|
||||
predicate: (currState: unknown, currAction: Action<unknown>) => boolean
|
||||
) {
|
||||
if (type === 'ACTION')
|
||||
return !stateSanitizer ? state : stateSanitizer(state, nextActionId - 1);
|
||||
|
@ -97,9 +136,14 @@ export function filterState(
|
|||
localFilter ||
|
||||
(filter && filter !== FilterState.DO_NOT_FILTER)
|
||||
) {
|
||||
const filteredStagedActionIds = [];
|
||||
const filteredComputedStates = [];
|
||||
const sanitizedActionsById = actionSanitizer && {};
|
||||
const filteredStagedActionIds: number[] = [];
|
||||
const filteredComputedStates: {
|
||||
state: unknown;
|
||||
error?: string | undefined;
|
||||
}[] = [];
|
||||
const sanitizedActionsById: {
|
||||
[id: number]: PerformAction<Action<unknown>>;
|
||||
} = actionSanitizer && {};
|
||||
const { actionsById } = state;
|
||||
const { computedStates } = state;
|
||||
|
4
packages/redux-devtools-core/src/utils/get-params.ts
Normal file
4
packages/redux-devtools-core/src/utils/get-params.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
declare module 'get-params' {
|
||||
function getParams(func: (...args: any[]) => unknown): string[];
|
||||
export default getParams;
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
import mapValues from 'lodash/mapValues';
|
||||
import jsan from 'jsan';
|
||||
import seralizeImmutable from 'remotedev-serialize/immutable/serialize';
|
||||
|
||||
function deprecate(param) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
`\`${param}\` parameter for Redux DevTools Extension is deprecated. Use \`serialize\` parameter instead:` +
|
||||
' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1'
|
||||
);
|
||||
}
|
||||
|
||||
export default function importState(
|
||||
state,
|
||||
{ deserializeState, deserializeAction, serialize }
|
||||
) {
|
||||
if (!state) return undefined;
|
||||
let parse = jsan.parse;
|
||||
if (serialize) {
|
||||
if (serialize.immutable) {
|
||||
parse = (v) =>
|
||||
jsan.parse(
|
||||
v,
|
||||
seralizeImmutable(serialize.immutable, serialize.refs).reviver
|
||||
);
|
||||
} else if (serialize.reviver) {
|
||||
parse = (v) => jsan.parse(v, serialize.reviver);
|
||||
}
|
||||
}
|
||||
|
||||
let preloadedState;
|
||||
let nextLiftedState = parse(state);
|
||||
if (nextLiftedState.payload) {
|
||||
if (nextLiftedState.preloadedState)
|
||||
preloadedState = parse(nextLiftedState.preloadedState);
|
||||
nextLiftedState = parse(nextLiftedState.payload);
|
||||
}
|
||||
if (deserializeState) {
|
||||
deprecate('deserializeState');
|
||||
if (typeof nextLiftedState.computedStates !== 'undefined') {
|
||||
nextLiftedState.computedStates = nextLiftedState.computedStates.map(
|
||||
(computedState) => ({
|
||||
...computedState,
|
||||
state: deserializeState(computedState.state),
|
||||
})
|
||||
);
|
||||
}
|
||||
if (typeof nextLiftedState.committedState !== 'undefined') {
|
||||
nextLiftedState.committedState = deserializeState(
|
||||
nextLiftedState.committedState
|
||||
);
|
||||
}
|
||||
if (typeof preloadedState !== 'undefined') {
|
||||
preloadedState = deserializeState(preloadedState);
|
||||
}
|
||||
}
|
||||
if (deserializeAction) {
|
||||
deprecate('deserializeAction');
|
||||
nextLiftedState.actionsById = mapValues(
|
||||
nextLiftedState.actionsById,
|
||||
(liftedAction) => ({
|
||||
...liftedAction,
|
||||
action: deserializeAction(liftedAction.action),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return { nextLiftedState, preloadedState };
|
||||
}
|
105
packages/redux-devtools-core/src/utils/importState.ts
Normal file
105
packages/redux-devtools-core/src/utils/importState.ts
Normal file
|
@ -0,0 +1,105 @@
|
|||
import mapValues from 'lodash/mapValues';
|
||||
import jsan from 'jsan';
|
||||
import { immutableSerialize } from 'redux-devtools-serialize';
|
||||
import { Action } from 'redux';
|
||||
import Immutable from 'immutable';
|
||||
import { State } from '../app/reducers/instances';
|
||||
|
||||
function deprecate(param: string) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
`\`${param}\` parameter for Redux DevTools Extension is deprecated. Use \`serialize\` parameter instead:` +
|
||||
' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1'
|
||||
);
|
||||
}
|
||||
|
||||
export default function importState(
|
||||
state: string,
|
||||
{
|
||||
deserializeState,
|
||||
deserializeAction,
|
||||
serialize,
|
||||
}: {
|
||||
deserializeState?: (state: string) => unknown;
|
||||
deserializeAction?: (action: string) => Action<unknown>;
|
||||
serialize?: {
|
||||
immutable?: typeof Immutable;
|
||||
refs?: (new (data: any) => unknown)[] | null;
|
||||
reviver?: (key: string, value: unknown) => unknown;
|
||||
};
|
||||
}
|
||||
) {
|
||||
if (!state) return undefined;
|
||||
let parse = jsan.parse;
|
||||
if (serialize) {
|
||||
if (serialize.immutable) {
|
||||
parse = (v) =>
|
||||
jsan.parse(
|
||||
v,
|
||||
immutableSerialize(serialize.immutable!, serialize.refs).reviver
|
||||
);
|
||||
} else if (serialize.reviver) {
|
||||
parse = (v) => jsan.parse(v, serialize.reviver);
|
||||
}
|
||||
}
|
||||
|
||||
let preloadedState: State | undefined;
|
||||
let nextLiftedState: State = parse(state) as State;
|
||||
if (
|
||||
((nextLiftedState as unknown) as {
|
||||
payload?: string;
|
||||
preloadedState?: string;
|
||||
}).payload
|
||||
) {
|
||||
if (
|
||||
((nextLiftedState as unknown) as {
|
||||
payload: string;
|
||||
preloadedState?: string;
|
||||
}).preloadedState
|
||||
)
|
||||
preloadedState = parse(
|
||||
((nextLiftedState as unknown) as {
|
||||
payload: string;
|
||||
preloadedState: string;
|
||||
}).preloadedState
|
||||
) as State;
|
||||
nextLiftedState = parse(
|
||||
((nextLiftedState as unknown) as {
|
||||
payload: string;
|
||||
}).payload
|
||||
) as State;
|
||||
}
|
||||
if (deserializeState) {
|
||||
deprecate('deserializeState');
|
||||
if (typeof nextLiftedState.computedStates !== 'undefined') {
|
||||
nextLiftedState.computedStates = nextLiftedState.computedStates.map(
|
||||
(computedState) => ({
|
||||
...computedState,
|
||||
state: deserializeState(computedState.state as string),
|
||||
})
|
||||
);
|
||||
}
|
||||
if (typeof nextLiftedState.committedState !== 'undefined') {
|
||||
nextLiftedState.committedState = deserializeState(
|
||||
nextLiftedState.committedState as string
|
||||
);
|
||||
}
|
||||
if (typeof preloadedState !== 'undefined') {
|
||||
preloadedState = deserializeState(
|
||||
(preloadedState as unknown) as string
|
||||
) as State;
|
||||
}
|
||||
}
|
||||
if (deserializeAction) {
|
||||
deprecate('deserializeAction');
|
||||
nextLiftedState.actionsById = mapValues(
|
||||
nextLiftedState.actionsById,
|
||||
(liftedAction) => ({
|
||||
...liftedAction,
|
||||
action: deserializeAction((liftedAction.action as unknown) as string),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return { nextLiftedState, preloadedState };
|
||||
}
|
|
@ -1,14 +1,24 @@
|
|||
import getParams from 'get-params';
|
||||
import jsan from 'jsan';
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
import seralizeImmutable from 'remotedev-serialize/immutable/serialize';
|
||||
import { immutableSerialize } from 'redux-devtools-serialize';
|
||||
import Immutable from 'immutable';
|
||||
import { Action } from 'redux';
|
||||
|
||||
export function generateId(id) {
|
||||
export function generateId(id: string | undefined) {
|
||||
return id || nanoid(7);
|
||||
}
|
||||
|
||||
function flatTree(obj, namespace = '') {
|
||||
let functions = [];
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
function flatTree(
|
||||
obj: { [key: string]: (...args: any[]) => unknown },
|
||||
namespace = ''
|
||||
) {
|
||||
let functions: {
|
||||
name: string;
|
||||
func: (...args: any[]) => unknown;
|
||||
args: string[];
|
||||
}[] = [];
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const prop = obj[key];
|
||||
if (typeof prop === 'function') {
|
||||
|
@ -24,18 +34,23 @@ function flatTree(obj, namespace = '') {
|
|||
return functions;
|
||||
}
|
||||
|
||||
export function getMethods(obj) {
|
||||
export function getMethods(obj: unknown) {
|
||||
if (typeof obj !== 'object') return undefined;
|
||||
let functions;
|
||||
let m;
|
||||
if (obj.__proto__) m = obj.__proto__.__proto__;
|
||||
if (!m) m = obj;
|
||||
let functions:
|
||||
| {
|
||||
name: string;
|
||||
args: string[];
|
||||
}[]
|
||||
| undefined;
|
||||
let m: { [key: string]: (...args: any[]) => unknown } | undefined;
|
||||
if ((obj as any).__proto__) m = (obj as any).__proto__.__proto__;
|
||||
if (!m) m = obj as any;
|
||||
|
||||
Object.getOwnPropertyNames(m).forEach((key) => {
|
||||
const propDescriptor = Object.getOwnPropertyDescriptor(m, key);
|
||||
if (!propDescriptor || 'get' in propDescriptor || 'set' in propDescriptor)
|
||||
return;
|
||||
const prop = m[key];
|
||||
const prop = m![key];
|
||||
if (typeof prop === 'function' && key !== 'constructor') {
|
||||
if (!functions) functions = [];
|
||||
functions.push({
|
||||
|
@ -47,15 +62,17 @@ export function getMethods(obj) {
|
|||
return functions;
|
||||
}
|
||||
|
||||
export function getActionsArray(actionCreators) {
|
||||
export function getActionsArray(actionCreators: {
|
||||
[key: string]: (...args: any[]) => unknown;
|
||||
}) {
|
||||
if (Array.isArray(actionCreators)) return actionCreators;
|
||||
return flatTree(actionCreators);
|
||||
}
|
||||
|
||||
/* eslint-disable no-new-func */
|
||||
const interpretArg = (arg) => new Function('return ' + arg)();
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
const interpretArg = (arg: string) => new Function('return ' + arg)();
|
||||
|
||||
function evalArgs(inArgs, restArgs) {
|
||||
function evalArgs(inArgs: string[], restArgs: string) {
|
||||
const args = inArgs.map(interpretArg);
|
||||
if (!restArgs) return args;
|
||||
const rest = interpretArg(restArgs);
|
||||
|
@ -63,8 +80,14 @@ function evalArgs(inArgs, restArgs) {
|
|||
throw new Error('rest must be an array');
|
||||
}
|
||||
|
||||
export function evalAction(action, actionCreators) {
|
||||
export function evalAction(
|
||||
action: string | { args: string[]; rest: string; selected: string },
|
||||
actionCreators: {
|
||||
[selected: string]: { func: (...args: any[]) => Action<unknown> };
|
||||
}
|
||||
) {
|
||||
if (typeof action === 'string') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
return new Function('return ' + action)();
|
||||
}
|
||||
|
||||
|
@ -73,12 +96,17 @@ export function evalAction(action, actionCreators) {
|
|||
return actionCreator(...args);
|
||||
}
|
||||
|
||||
export function evalMethod(action, obj) {
|
||||
export function evalMethod(
|
||||
action: string | { args: string[]; rest: string; name: string },
|
||||
obj: unknown
|
||||
) {
|
||||
if (typeof action === 'string') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
return new Function('return ' + action).call(obj);
|
||||
}
|
||||
|
||||
const args = evalArgs(action.args, action.rest);
|
||||
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||
return new Function('args', `return this.${action.name}(args)`).apply(
|
||||
obj,
|
||||
args
|
||||
|
@ -86,7 +114,7 @@ export function evalMethod(action, obj) {
|
|||
}
|
||||
/* eslint-enable */
|
||||
|
||||
function tryCatchStringify(obj) {
|
||||
function tryCatchStringify(obj: unknown) {
|
||||
try {
|
||||
return JSON.stringify(obj);
|
||||
} catch (err) {
|
||||
|
@ -94,11 +122,26 @@ function tryCatchStringify(obj) {
|
|||
if (process.env.NODE_ENV !== 'production')
|
||||
console.log('Failed to stringify', err);
|
||||
/* eslint-enable no-console */
|
||||
return jsan.stringify(obj, null, null, { circular: '[CIRCULAR]' });
|
||||
return jsan.stringify(
|
||||
obj,
|
||||
(null as unknown) as undefined,
|
||||
(null as unknown) as undefined,
|
||||
({
|
||||
circular: '[CIRCULAR]',
|
||||
} as unknown) as boolean
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function stringify(obj, serialize) {
|
||||
export function stringify(
|
||||
obj: unknown,
|
||||
serialize?:
|
||||
| {
|
||||
replacer?: (key: string, value: unknown) => unknown;
|
||||
options?: unknown | boolean;
|
||||
}
|
||||
| true
|
||||
) {
|
||||
if (typeof serialize === 'undefined') {
|
||||
return tryCatchStringify(obj);
|
||||
}
|
||||
|
@ -106,23 +149,44 @@ export function stringify(obj, serialize) {
|
|||
return jsan.stringify(
|
||||
obj,
|
||||
function (key, value) {
|
||||
if (value && typeof value.toJS === 'function') return value.toJS();
|
||||
if (value && typeof (value as any).toJS === 'function')
|
||||
return (value as any).toJS();
|
||||
return value;
|
||||
},
|
||||
null,
|
||||
(null as unknown) as undefined,
|
||||
true
|
||||
);
|
||||
}
|
||||
return jsan.stringify(obj, serialize.replacer, null, serialize.options);
|
||||
return jsan.stringify(
|
||||
obj,
|
||||
serialize.replacer,
|
||||
(null as unknown) as undefined,
|
||||
serialize.options as boolean
|
||||
);
|
||||
}
|
||||
|
||||
export function getSeralizeParameter(config, param) {
|
||||
export function getSeralizeParameter(
|
||||
config: {
|
||||
serialize?: {
|
||||
immutable?: typeof Immutable;
|
||||
refs?: (new (data: any) => unknown)[] | null;
|
||||
replacer?: (key: string, value: unknown) => unknown;
|
||||
options?: unknown | boolean;
|
||||
};
|
||||
},
|
||||
param: string
|
||||
):
|
||||
| {
|
||||
replacer?: (key: string, value: unknown) => unknown;
|
||||
options: unknown | boolean;
|
||||
}
|
||||
| undefined {
|
||||
const serialize = config.serialize;
|
||||
if (serialize) {
|
||||
if (serialize === true) return { options: true };
|
||||
if (serialize.immutable) {
|
||||
return {
|
||||
replacer: seralizeImmutable(serialize.immutable, serialize.refs)
|
||||
replacer: immutableSerialize(serialize.immutable, serialize.refs)
|
||||
.replacer,
|
||||
options: serialize.options || true,
|
||||
};
|
||||
|
@ -131,7 +195,12 @@ export function getSeralizeParameter(config, param) {
|
|||
return { replacer: serialize.replacer, options: serialize.options || true };
|
||||
}
|
||||
|
||||
const value = config[param];
|
||||
const value = (config as {
|
||||
[param: string]: {
|
||||
replacer?: (key: string, value: unknown) => unknown;
|
||||
options: unknown | boolean;
|
||||
};
|
||||
})[param];
|
||||
if (typeof value === 'undefined') return undefined;
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
|
@ -139,12 +208,15 @@ export function getSeralizeParameter(config, param) {
|
|||
' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1'
|
||||
);
|
||||
|
||||
if (typeof serializeState === 'boolean') return { options: value };
|
||||
if (typeof serializeState === 'function') return { replacer: value };
|
||||
return value;
|
||||
}
|
||||
|
||||
export function getStackTrace(config, toExcludeFromTrace) {
|
||||
export function getStackTrace(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
config: { trace?: () => {}; traceLimit: number },
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
toExcludeFromTrace?: Function | undefined
|
||||
) {
|
||||
if (!config.trace) return undefined;
|
||||
if (typeof config.trace === 'function') return config.trace();
|
||||
|
||||
|
@ -169,7 +241,7 @@ export function getStackTrace(config, toExcludeFromTrace) {
|
|||
typeof Error.stackTraceLimit !== 'number' ||
|
||||
Error.stackTraceLimit > traceLimit
|
||||
) {
|
||||
const frames = stack.split('\n');
|
||||
const frames = stack!.split('\n');
|
||||
if (frames.length > traceLimit) {
|
||||
stack = frames
|
||||
.slice(0, traceLimit + extraFrames + (frames[0] === 'Error' ? 1 : 0))
|
|
@ -1 +0,0 @@
|
|||
module.exports = {};
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
import { mount } from 'enzyme';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
// import { mountToJson } from 'enzyme-to-json';
|
||||
import App from '../src/app/containers/App';
|
||||
import api from '../src/app/middlewares/api';
|
||||
|
@ -10,7 +10,7 @@ import rootReducer from '../src/app/reducers';
|
|||
import { DATA_TYPE_KEY } from '../src/app/constants/dataTypes';
|
||||
import stringifyJSON from '../src/app/utils/stringifyJSON';
|
||||
|
||||
let wrapper;
|
||||
let wrapper: ReactWrapper<unknown, unknown, Component>;
|
||||
|
||||
const store = createStore(rootReducer, applyMiddleware(exportState, api));
|
||||
|
4
packages/redux-devtools-core/test/tsconfig.json
Normal file
4
packages/redux-devtools-core/test/tsconfig.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.react.base.json",
|
||||
"include": ["../src", "."]
|
||||
}
|
7
packages/redux-devtools-core/tsconfig.json
Normal file
7
packages/redux-devtools-core/tsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../tsconfig.react.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
4
packages/redux-devtools-core/tsconfig.webpack.json
Normal file
4
packages/redux-devtools-core/tsconfig.webpack.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["webpack.config.ts", "webpack.config.umd.ts"]
|
||||
}
|
|
@ -1,14 +1,15 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
import * as path from 'path';
|
||||
import * as webpack from 'webpack';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
||||
|
||||
module.exports = (env = {}) => ({
|
||||
module.exports = (env: { development?: boolean; platform?: string } = {}) => ({
|
||||
mode: env.development ? 'development' : 'production',
|
||||
entry: {
|
||||
app: './index.js',
|
||||
app: './src/index',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'build/' + env.platform),
|
||||
path: path.resolve(__dirname, `build/${env.platform as string}`),
|
||||
publicPath: '',
|
||||
filename: 'js/[name].js',
|
||||
sourceMapFilename: 'js/[name].map',
|
||||
|
@ -16,7 +17,7 @@ module.exports = (env = {}) => ({
|
|||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
test: /\.(js|ts)x?$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
|
@ -44,6 +45,9 @@ module.exports = (env = {}) => ({
|
|||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
|
@ -56,6 +60,11 @@ module.exports = (env = {}) => ({
|
|||
new HtmlWebpackPlugin({
|
||||
template: 'assets/index.html',
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
configFile: 'tsconfig.json',
|
||||
},
|
||||
}),
|
||||
],
|
||||
optimization: {
|
||||
minimize: false,
|
|
@ -1,10 +1,11 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
import * as path from 'path';
|
||||
import * as webpack from 'webpack';
|
||||
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
||||
|
||||
module.exports = (env = {}) => ({
|
||||
module.exports = (env: { production?: boolean } = {}) => ({
|
||||
mode: env.production ? 'production' : 'development',
|
||||
entry: {
|
||||
app: ['./src/app/index.js'],
|
||||
app: ['./src/app/index'],
|
||||
},
|
||||
output: {
|
||||
library: 'ReduxDevTools',
|
||||
|
@ -18,7 +19,7 @@ module.exports = (env = {}) => ({
|
|||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
test: /\.(js|ts)x?$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
|
@ -41,6 +42,9 @@ module.exports = (env = {}) => ({
|
|||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
|
@ -48,6 +52,11 @@ module.exports = (env = {}) => ({
|
|||
PLATFORM: JSON.stringify('web'),
|
||||
},
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: {
|
||||
configFile: 'tsconfig.json',
|
||||
},
|
||||
}),
|
||||
],
|
||||
externals: {
|
||||
react: {
|
|
@ -25,7 +25,7 @@ export interface TabComponentProps<S, A extends Action<unknown>> {
|
|||
base16Theme: Base16Theme;
|
||||
invertTheme: boolean;
|
||||
isWideLayout: boolean;
|
||||
dataTypeKey: string | undefined;
|
||||
dataTypeKey: string | symbol | undefined;
|
||||
delta: Delta | null | undefined | false;
|
||||
action: A;
|
||||
nextState: S;
|
||||
|
@ -67,7 +67,7 @@ interface Props<S, A extends Action<unknown>> {
|
|||
actions: { [actionId: number]: PerformAction<A> };
|
||||
selectedActionId: number | null;
|
||||
startActionId: number | null;
|
||||
dataTypeKey: string | undefined;
|
||||
dataTypeKey: string | symbol | undefined;
|
||||
monitorState: DevtoolsInspectorState;
|
||||
updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;
|
||||
styling: StylingFunction;
|
||||
|
|
|
@ -128,7 +128,7 @@ function createThemeState<S, A extends Action<unknown>>(
|
|||
return { base16Theme, styling };
|
||||
}
|
||||
|
||||
interface ExternalProps<S, A extends Action<unknown>> {
|
||||
export interface ExternalProps<S, A extends Action<unknown>> {
|
||||
dispatch: Dispatch<
|
||||
DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState>
|
||||
>;
|
||||
|
@ -142,7 +142,7 @@ interface ExternalProps<S, A extends Action<unknown>> {
|
|||
hideMainButtons?: boolean;
|
||||
hideActionButtons?: boolean;
|
||||
invertTheme: boolean;
|
||||
dataTypeKey?: string;
|
||||
dataTypeKey?: string | symbol;
|
||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ export interface DevtoolsInspectorProps<S, A extends Action<unknown>>
|
|||
hideMainButtons?: boolean;
|
||||
hideActionButtons?: boolean;
|
||||
invertTheme: boolean;
|
||||
dataTypeKey?: string;
|
||||
dataTypeKey?: string | symbol;
|
||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { DevtoolsInspectorProps } from './DevtoolsInspector';
|
|||
const UPDATE_MONITOR_STATE =
|
||||
'@@redux-devtools-inspector-monitor/UPDATE_MONITOR_STATE';
|
||||
|
||||
interface UpdateMonitorStateAction {
|
||||
export interface UpdateMonitorStateAction {
|
||||
type: typeof UPDATE_MONITOR_STATE;
|
||||
monitorState: Partial<DevtoolsInspectorState>;
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ interface Props {
|
|||
expandable: boolean
|
||||
) => React.ReactNode;
|
||||
isWideLayout: boolean;
|
||||
dataTypeKey: string | undefined;
|
||||
dataTypeKey: string | symbol | undefined;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
|
|
@ -73,7 +73,7 @@ const getItemString = (
|
|||
styling: StylingFunction,
|
||||
type: string,
|
||||
data: any,
|
||||
dataTypeKey: string | undefined,
|
||||
dataTypeKey: string | symbol | undefined,
|
||||
isWideLayout: boolean,
|
||||
isDiff?: boolean
|
||||
) => (
|
||||
|
|
|
@ -35,3 +35,4 @@ export default function (
|
|||
serialize: serialize,
|
||||
};
|
||||
}
|
||||
export { default as serialize } from './serialize';
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user