mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-02-16 19:40:58 +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 { default as tree } from './tree/tree';
|
||||||
|
export type { InputOptions, NodeWithId } from './tree/tree';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import d3tooltip from 'd3tooltip';
|
import d3tooltip from 'd3tooltip';
|
||||||
|
|
||||||
interface InputOptions {
|
export interface InputOptions {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
state?: {} | null;
|
state?: {} | null;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
@ -34,7 +34,7 @@ interface InputOptions {
|
||||||
widthBetweenNodesCoeff: number;
|
widthBetweenNodesCoeff: number;
|
||||||
transitionDuration: number;
|
transitionDuration: number;
|
||||||
blinkDuration: number;
|
blinkDuration: number;
|
||||||
onClickText: () => void;
|
onClickText: (datum: NodeWithId) => void;
|
||||||
tooltipOptions: {
|
tooltipOptions: {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
left?: number | undefined;
|
left?: number | undefined;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as charts from './charts';
|
import * as charts from './charts';
|
||||||
|
|
||||||
export { tree } from './charts';
|
export { tree } from './charts';
|
||||||
|
export type { InputOptions, NodeWithId } from './charts';
|
||||||
|
|
||||||
export default charts;
|
export default charts;
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export { default } from './Tabs';
|
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 Form } from './Form';
|
||||||
export { default as Select } from './Select';
|
export { default as Select } from './Select';
|
||||||
export { default as Slider } from './Slider';
|
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 SegmentedControl } from './SegmentedControl';
|
||||||
export { default as Notification } from './Notification';
|
export { default as Notification } from './Notification';
|
||||||
export * from './Toolbar';
|
export * from './Toolbar';
|
||||||
|
@ -14,3 +14,4 @@ export * from './Toolbar';
|
||||||
import color from './utils/color';
|
import color from './utils/color';
|
||||||
export const effects = { color };
|
export const effects = { color };
|
||||||
export { default as createStyledComponent } from './utils/createStyledComponent';
|
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 baseSchemes from 'base16';
|
||||||
import * as additionalSchemes from '../colorSchemes';
|
import * as additionalSchemes from '../colorSchemes';
|
||||||
import invertColors from '../utils/invertColors';
|
import invertColors from '../utils/invertColors';
|
||||||
import { Theme } from '../themes/default';
|
import { Theme as ThemeBase } from '../themes/default';
|
||||||
|
|
||||||
export const schemes = { ...baseSchemes, ...additionalSchemes };
|
export const schemes = { ...baseSchemes, ...additionalSchemes };
|
||||||
export const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule`
|
export const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule`
|
||||||
export const listThemes = () => Object.keys(themes);
|
export const listThemes = () => Object.keys(themes);
|
||||||
|
|
||||||
|
export type Theme = keyof typeof themes;
|
||||||
|
export type Scheme = keyof typeof schemes;
|
||||||
|
|
||||||
export interface ThemeData {
|
export interface ThemeData {
|
||||||
theme: keyof typeof themes;
|
theme: keyof typeof themes;
|
||||||
scheme: keyof typeof schemes;
|
scheme: keyof typeof schemes;
|
||||||
light: boolean;
|
light: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ThemeFromProvider extends Theme {
|
export interface ThemeFromProvider extends ThemeBase {
|
||||||
type: keyof typeof themes;
|
type: keyof typeof themes;
|
||||||
light: boolean;
|
light: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import * as themes from 'redux-devtools-themes';
|
||||||
import { Base16Theme } from 'react-base16-styling';
|
import { Base16Theme } from 'react-base16-styling';
|
||||||
import { ChartMonitorState } from './reducers';
|
import { ChartMonitorState } from './reducers';
|
||||||
import { Primitive } from 'd3';
|
import { Primitive } from 'd3';
|
||||||
|
import { NodeWithId } from 'd3-state-visualizer/lib/charts/tree/tree';
|
||||||
|
|
||||||
const wrapperStyle = {
|
const wrapperStyle = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -25,6 +26,7 @@ export interface Props<S, A extends Action<unknown>>
|
||||||
isSorted: boolean;
|
isSorted: boolean;
|
||||||
heightBetweenNodesCoeff: number;
|
heightBetweenNodesCoeff: number;
|
||||||
widthBetweenNodesCoeff: number;
|
widthBetweenNodesCoeff: number;
|
||||||
|
onClickText: (datum: NodeWithId) => void;
|
||||||
tooltipOptions: {
|
tooltipOptions: {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
offset: {
|
offset: {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Base16Theme } from 'react-base16-styling';
|
||||||
import reducer, { ChartMonitorState } from './reducers';
|
import reducer, { ChartMonitorState } from './reducers';
|
||||||
import Chart, { Props } from './Chart';
|
import Chart, { Props } from './Chart';
|
||||||
import { Primitive } from 'd3';
|
import { Primitive } from 'd3';
|
||||||
|
import { NodeWithId } from 'd3-state-visualizer/lib/charts/tree/tree';
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const { reset, rollback, commit, sweep, toggleAction } = ActionCreators;
|
const { reset, rollback, commit, sweep, toggleAction } = ActionCreators;
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ export interface ChartMonitorProps<S, A extends Action<unknown>>
|
||||||
isSorted: boolean;
|
isSorted: boolean;
|
||||||
heightBetweenNodesCoeff: number;
|
heightBetweenNodesCoeff: number;
|
||||||
widthBetweenNodesCoeff: number;
|
widthBetweenNodesCoeff: number;
|
||||||
|
onClickText: (datum: NodeWithId) => void;
|
||||||
tooltipOptions: unknown;
|
tooltipOptions: unknown;
|
||||||
style: {
|
style: {
|
||||||
width: number;
|
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"]
|
"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",
|
"name": "redux-devtools-core",
|
||||||
"version": "1.0.0-4",
|
"version": "1.0.0-4",
|
||||||
"description": "Reusable functions of Redux DevTools",
|
"description": "Reusable functions of Redux DevTools",
|
||||||
"scripts": {
|
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-core",
|
||||||
"start": "webpack-dev-server --hot --inline --env.development --env.platform=web --progress",
|
"bugs": {
|
||||||
"build:web": "rimraf ./build/web && webpack -p --env.platform=web --progress",
|
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"main": "lib/index.js",
|
"license": "MIT",
|
||||||
|
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
||||||
"files": [
|
"files": [
|
||||||
"src",
|
"src",
|
||||||
"lib",
|
"lib",
|
||||||
"umd"
|
"umd"
|
||||||
],
|
],
|
||||||
"jest": {
|
"main": "lib/index.js",
|
||||||
"setupFilesAfterEnv": [
|
"types": "lib/index.d.ts",
|
||||||
"<rootDir>/test/setup.js"
|
|
||||||
],
|
|
||||||
"moduleNameMapper": {
|
|
||||||
"\\.(css|scss)$": "<rootDir>/test/__mocks__/styleMock.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||||
},
|
},
|
||||||
"author": "Mihail Diordiev <zalmoxisus@gmail.com> (https://github.com/zalmoxisus)",
|
"scripts": {
|
||||||
"license": "MIT",
|
"start": "webpack-dev-server --hot --inline --env.development --env.platform=web --progress",
|
||||||
"bugs": {
|
"build": "npm run build:types && npm run build:js && npm run build:web && npm run build:umd && npm run build:umd:min",
|
||||||
"url": "https://github.com/reduxjs/redux-devtools/issues"
|
"build:types": "tsc --emitDeclarationOnly",
|
||||||
},
|
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
|
||||||
"homepage": "https://github.com/reduxjs/redux-devtools",
|
"build:web": "rimraf ./build/web && webpack -p --env.platform=web --progress",
|
||||||
"devDependencies": {
|
"build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.ts",
|
||||||
"@babel/cli": "^7.10.5",
|
"build:umd:min": "webpack --env.production --progress --config webpack.config.umd.ts",
|
||||||
"@babel/core": "^7.11.1",
|
"clean": "rimraf lib",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
"test": "jest",
|
||||||
"@babel/preset-env": "^7.11.0",
|
"lint": "eslint . --ext .ts,.tsx",
|
||||||
"@babel/preset-react": "^7.10.4",
|
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||||
"babel-loader": "^8.1.0",
|
"type-check": "tsc --noEmit",
|
||||||
"css-loader": "^4.2.1",
|
"type-check:watch": "npm run type-check -- --watch",
|
||||||
"enzyme": "^3.11.0",
|
"preversion": "npm run type-check && npm run lint && npm run test",
|
||||||
"enzyme-adapter-react-16": "^1.15.3",
|
"prepublishOnly": "npm run clean && npm run build"
|
||||||
"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"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"d3-state-visualizer": "^1.3.4",
|
"d3-state-visualizer": "^1.3.4",
|
||||||
|
@ -90,6 +64,34 @@
|
||||||
"socketcluster-client": "^14.3.1",
|
"socketcluster-client": "^14.3.1",
|
||||||
"styled-components": "^5.1.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": {
|
"peerDependencies": {
|
||||||
"react": "^16.3.0"
|
"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 DispatcherButton from './buttons/DispatcherButton';
|
||||||
import SliderButton from './buttons/SliderButton';
|
import SliderButton from './buttons/SliderButton';
|
||||||
import MonitorSelector from './MonitorSelector';
|
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 = {
|
static propTypes = {
|
||||||
dispatcherIsOpen: PropTypes.bool,
|
dispatcherIsOpen: PropTypes.bool,
|
||||||
sliderIsOpen: PropTypes.bool,
|
sliderIsOpen: PropTypes.bool,
|
||||||
options: PropTypes.object.isRequired,
|
options: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return (
|
return (
|
||||||
nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen ||
|
nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen ||
|
||||||
nextProps.sliderIsOpen !== this.props.sliderIsOpen ||
|
nextProps.sliderIsOpen !== this.props.sliderIsOpen ||
|
|
@ -1,8 +1,6 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Tabs, Toolbar, Button, Divider } from 'devui';
|
import { Tabs, Toolbar, Button, Divider } from 'devui';
|
||||||
import { bindActionCreators } from 'redux';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { GoBook } from 'react-icons/go';
|
import { GoBook } from 'react-icons/go';
|
||||||
import { IoMdText } from 'react-icons/io';
|
import { IoMdText } from 'react-icons/io';
|
||||||
import { TiSocialTwitter } from 'react-icons/ti';
|
import { TiSocialTwitter } from 'react-icons/ti';
|
||||||
|
@ -11,13 +9,14 @@ import { changeSection } from '../actions';
|
||||||
|
|
||||||
const tabs = [{ name: 'Actions' }, { name: 'Reports' }, { name: 'Settings' }];
|
const tabs = [{ name: 'Actions' }, { name: 'Reports' }, { name: 'Settings' }];
|
||||||
|
|
||||||
class Header extends Component {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
static propTypes = {
|
interface OwnProps {
|
||||||
section: PropTypes.string.isRequired,
|
readonly section: string;
|
||||||
changeSection: PropTypes.func.isRequired,
|
}
|
||||||
};
|
type Props = DispatchProps & OwnProps;
|
||||||
|
|
||||||
openLink = (url) => () => {
|
class Header extends Component<Props> {
|
||||||
|
openLink = (url: string) => () => {
|
||||||
window.open(url);
|
window.open(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,10 +68,8 @@ class Header extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
changeSection,
|
||||||
changeSection: bindActionCreators(changeSection, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
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 React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { Container, Form } from 'devui';
|
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',
|
type: 'object',
|
||||||
required: [],
|
required: [],
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -37,37 +58,24 @@ const uiSchema = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
class Connection extends Component {
|
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||||
static propTypes = {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
saveSettings: PropTypes.func.isRequired,
|
type Props = StateProps & DispatchProps;
|
||||||
options: PropTypes.object.isRequired,
|
|
||||||
type: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
interface FormData extends ConnectionOptions {
|
||||||
super(props);
|
readonly type: ConnectionType;
|
||||||
this.state = this.setFormData(props.type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
interface State {
|
||||||
return this.state !== nextState;
|
readonly formData: FormData;
|
||||||
|
readonly type: ConnectionType;
|
||||||
|
readonly schema: Schema;
|
||||||
|
readonly changed: boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
export class Connection extends Component<Props, State> {
|
||||||
if (this.props.options !== nextProps.options) {
|
setFormData = (type: ConnectionType, changed?: boolean) => {
|
||||||
this.setState({
|
let schema: Schema;
|
||||||
formData: { ...nextProps.options, type: nextProps.type },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSave = (data) => {
|
|
||||||
this.props.saveSettings(data.formData);
|
|
||||||
this.setState({ changed: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
setFormData = (type, changed) => {
|
|
||||||
let schema;
|
|
||||||
if (type !== 'custom') {
|
if (type !== 'custom') {
|
||||||
schema = {
|
schema = {
|
||||||
type: 'object',
|
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 formData = data.formData;
|
||||||
const type = formData.type;
|
const type = formData.type;
|
||||||
if (type !== this.state.type) {
|
if (type !== this.state.type) {
|
||||||
|
@ -119,14 +146,10 @@ class Connection extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const mapStateToProps = (state: StoreState) => state.connection;
|
||||||
return state.connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
saveSettings: saveSocketSettings,
|
||||||
saveSettings: bindActionCreators(saveSocketSettings, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Connection);
|
export default connect(mapStateToProps, actionCreators)(Connection);
|
|
@ -1,17 +1,15 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { Container, Form } from 'devui';
|
import { Container, Form } from 'devui';
|
||||||
import { listSchemes, listThemes } from 'devui/lib/utils/theme';
|
import { listSchemes, listThemes } from 'devui/lib/utils/theme';
|
||||||
import { changeTheme } from '../../actions';
|
import { changeTheme } from '../../actions';
|
||||||
|
import { StoreState } from '../../reducers';
|
||||||
|
|
||||||
class Themes extends Component {
|
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||||
static propTypes = {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
changeTheme: PropTypes.func.isRequired,
|
type Props = StateProps & DispatchProps;
|
||||||
theme: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
export class Themes extends Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const theme = this.props.theme;
|
const theme = this.props.theme;
|
||||||
const formData = {
|
const formData = {
|
||||||
|
@ -49,16 +47,12 @@ class Themes extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
return {
|
|
||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
changeTheme,
|
||||||
changeTheme: bindActionCreators(changeTheme, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
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 React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
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 { Button, Toolbar, Divider } from 'devui';
|
||||||
|
import { Action } from 'redux';
|
||||||
import RecordButton from './buttons/RecordButton';
|
import RecordButton from './buttons/RecordButton';
|
||||||
import PersistButton from './buttons/PersistButton';
|
import PersistButton from './buttons/PersistButton';
|
||||||
import LockButton from './buttons/LockButton';
|
import LockButton from './buttons/LockButton';
|
||||||
import InstanceSelector from './InstanceSelector';
|
import InstanceSelector from './InstanceSelector';
|
||||||
import SyncButton from './buttons/SyncButton';
|
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;
|
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 = {
|
static propTypes = {
|
||||||
// shouldSync: PropTypes.bool,
|
// shouldSync: PropTypes.bool,
|
||||||
liftedState: PropTypes.object.isRequired,
|
liftedState: PropTypes.object.isRequired,
|
||||||
|
@ -18,7 +27,7 @@ export default class TopButtons extends Component {
|
||||||
options: PropTypes.object.isRequired,
|
options: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return (
|
return (
|
||||||
nextProps.options !== this.props.options ||
|
nextProps.options !== this.props.options ||
|
||||||
nextProps.liftedState !== this.props.liftedState
|
nextProps.liftedState !== this.props.liftedState
|
|
@ -1,18 +1,17 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { Button } from 'devui';
|
import { Button } from 'devui';
|
||||||
import { FaTerminal } from 'react-icons/fa';
|
import { FaTerminal } from 'react-icons/fa';
|
||||||
import { toggleDispatcher } from '../../actions';
|
import { toggleDispatcher } from '../../actions';
|
||||||
|
|
||||||
class DispatcherButton extends Component {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
static propTypes = {
|
interface OwnProps {
|
||||||
dispatcherIsOpen: PropTypes.bool,
|
dispatcherIsOpen: boolean;
|
||||||
toggleDispatcher: PropTypes.func.isRequired,
|
}
|
||||||
};
|
type Props = DispatchProps & OwnProps;
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
class DispatcherButton extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen;
|
return nextProps.dispatcherIsOpen !== this.props.dispatcherIsOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +31,8 @@ class DispatcherButton extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
toggleDispatcher,
|
||||||
toggleDispatcher: bindActionCreators(toggleDispatcher, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
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 React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Button } from 'devui';
|
import { Button } from 'devui';
|
||||||
import { IoIosLock } from 'react-icons/io';
|
import { IoIosLock } from 'react-icons/io';
|
||||||
import { lockChanges } from '../../actions';
|
import { lockChanges, StoreAction } from '../../actions';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
|
||||||
class LockButton extends Component {
|
type DispatchProps = ReturnType<typeof mapDispatchToProps>;
|
||||||
static propTypes = {
|
interface OwnProps {
|
||||||
locked: PropTypes.bool,
|
locked: boolean | undefined;
|
||||||
disabled: PropTypes.bool,
|
disabled: boolean;
|
||||||
lockChanges: PropTypes.func.isRequired,
|
}
|
||||||
};
|
type Props = DispatchProps & OwnProps;
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
class LockButton extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return nextProps.locked !== this.props.locked;
|
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 {
|
return {
|
||||||
lockChanges: () => dispatch(lockChanges(!ownProps.locked)),
|
lockChanges: () => dispatch(lockChanges(!ownProps.locked)),
|
||||||
};
|
};
|
|
@ -1,26 +1,26 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { Button } from 'devui';
|
import { Button } from 'devui';
|
||||||
import { FaThumbtack } from 'react-icons/fa';
|
import { FaThumbtack } from 'react-icons/fa';
|
||||||
import { togglePersist } from '../../actions';
|
import { togglePersist } from '../../actions';
|
||||||
|
import { StoreState } from '../../reducers';
|
||||||
|
|
||||||
class LockButton extends Component {
|
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||||
static propTypes = {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
persisted: PropTypes.bool,
|
interface OwnProps {
|
||||||
disabled: PropTypes.bool,
|
disabled?: boolean;
|
||||||
onClick: PropTypes.func.isRequired,
|
}
|
||||||
};
|
type Props = StateProps & DispatchProps & OwnProps;
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
class LockButton extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return nextProps.persisted !== this.props.persisted;
|
return nextProps.persisted !== this.props.persisted;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
toolbar
|
|
||||||
tooltipPosition="bottom"
|
tooltipPosition="bottom"
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
mark={this.props.persisted && 'base0D'}
|
mark={this.props.persisted && 'base0D'}
|
||||||
|
@ -37,16 +37,12 @@ class LockButton extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
return {
|
|
||||||
persisted: state.instances.persisted,
|
persisted: state.instances.persisted,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
onClick: togglePersist,
|
||||||
onClick: bindActionCreators(togglePersist, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(LockButton);
|
export default connect(mapStateToProps, actionCreators)(LockButton);
|
|
@ -7,8 +7,8 @@ export default class PrintButton extends Component {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePrint() {
|
handlePrint = () => {
|
||||||
const d3svg = document.getElementById('d3svg');
|
const d3svg = (document.getElementById('d3svg') as unknown) as SVGGElement;
|
||||||
if (!d3svg) {
|
if (!d3svg) {
|
||||||
window.print();
|
window.print();
|
||||||
return;
|
return;
|
||||||
|
@ -17,11 +17,11 @@ export default class PrintButton extends Component {
|
||||||
const initHeight = d3svg.style.height;
|
const initHeight = d3svg.style.height;
|
||||||
const initWidth = d3svg.style.width;
|
const initWidth = d3svg.style.width;
|
||||||
const box = d3svg.getBBox();
|
const box = d3svg.getBBox();
|
||||||
d3svg.style.height = box.height;
|
d3svg.style.height = `${box.height}`;
|
||||||
d3svg.style.width = box.width;
|
d3svg.style.width = `${box.width}`;
|
||||||
|
|
||||||
const g = d3svg.firstChild;
|
const g = d3svg.firstChild! as SVGGElement;
|
||||||
const initTransform = g.getAttribute('transform');
|
const initTransform = g.getAttribute('transform')!;
|
||||||
g.setAttribute(
|
g.setAttribute(
|
||||||
'transform',
|
'transform',
|
||||||
initTransform.replace(/.+scale\(/, 'translate(57, 10) scale(')
|
initTransform.replace(/.+scale\(/, 'translate(57, 10) scale(')
|
||||||
|
@ -32,7 +32,7 @@ export default class PrintButton extends Component {
|
||||||
d3svg.style.height = initHeight;
|
d3svg.style.height = initHeight;
|
||||||
d3svg.style.width = initWidth;
|
d3svg.style.width = initWidth;
|
||||||
g.setAttribute('transform', initTransform);
|
g.setAttribute('transform', initTransform);
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
|
@ -1,17 +1,18 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Button } from 'devui';
|
import { Button } from 'devui';
|
||||||
import { MdFiberManualRecord } from 'react-icons/md';
|
import { MdFiberManualRecord } from 'react-icons/md';
|
||||||
import { pauseRecording } from '../../actions';
|
import { pauseRecording, StoreAction } from '../../actions';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
|
||||||
class RecordButton extends Component {
|
type DispatchProps = ReturnType<typeof mapDispatchToProps>;
|
||||||
static propTypes = {
|
interface OwnProps {
|
||||||
paused: PropTypes.bool,
|
paused: boolean | undefined;
|
||||||
pauseRecording: PropTypes.func.isRequired,
|
}
|
||||||
};
|
type Props = DispatchProps & OwnProps;
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
class RecordButton extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return nextProps.paused !== this.props.paused;
|
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 {
|
return {
|
||||||
pauseRecording: () => dispatch(pauseRecording(!ownProps.paused)),
|
pauseRecording: () => dispatch(pauseRecording(!ownProps.paused)),
|
||||||
};
|
};
|
|
@ -1,18 +1,17 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { Button } from 'devui';
|
import { Button } from 'devui';
|
||||||
import { MdAvTimer } from 'react-icons/md';
|
import { MdAvTimer } from 'react-icons/md';
|
||||||
import { toggleSlider } from '../../actions';
|
import { toggleSlider } from '../../actions';
|
||||||
|
|
||||||
class SliderButton extends Component {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
static propTypes = {
|
interface OwnProps {
|
||||||
isOpen: PropTypes.bool,
|
isOpen: boolean;
|
||||||
toggleSlider: PropTypes.func.isRequired,
|
}
|
||||||
};
|
type Props = DispatchProps & OwnProps;
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
class SliderButton extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return nextProps.isOpen !== this.props.isOpen;
|
return nextProps.isOpen !== this.props.isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +29,8 @@ class SliderButton extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
toggleSlider,
|
||||||
toggleSlider: bindActionCreators(toggleSlider, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
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';
|
import socketCluster from 'socketcluster-client';
|
||||||
|
|
||||||
|
interface States {
|
||||||
|
CLOSED: 'closed';
|
||||||
|
CONNECTING: 'connecting';
|
||||||
|
OPEN: 'open';
|
||||||
|
AUTHENTICATED: 'authenticated';
|
||||||
|
PENDING: 'pending';
|
||||||
|
UNAUTHENTICATED: 'unauthenticated';
|
||||||
|
}
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
CLOSED,
|
CLOSED,
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
|
@ -7,7 +16,7 @@ export const {
|
||||||
AUTHENTICATED,
|
AUTHENTICATED,
|
||||||
PENDING,
|
PENDING,
|
||||||
UNAUTHENTICATED,
|
UNAUTHENTICATED,
|
||||||
} = socketCluster.SCClientSocket;
|
} = (socketCluster.SCClientSocket as unknown) as States;
|
||||||
export const CONNECT_REQUEST = 'socket/CONNECT_REQUEST';
|
export const CONNECT_REQUEST = 'socket/CONNECT_REQUEST';
|
||||||
export const CONNECT_SUCCESS = 'socket/CONNECT_SUCCESS';
|
export const CONNECT_SUCCESS = 'socket/CONNECT_SUCCESS';
|
||||||
export const CONNECT_ERROR = 'socket/CONNECT_ERROR';
|
export const CONNECT_ERROR = 'socket/CONNECT_ERROR';
|
|
@ -1,7 +1,5 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { Container } from 'devui';
|
import { Container } from 'devui';
|
||||||
import SliderMonitor from './monitors/Slider';
|
import SliderMonitor from './monitors/Slider';
|
||||||
import { liftedDispatch as liftedDispatchAction, getReport } from '../actions';
|
import { liftedDispatch as liftedDispatchAction, getReport } from '../actions';
|
||||||
|
@ -10,8 +8,13 @@ import DevTools from '../containers/DevTools';
|
||||||
import Dispatcher from './monitors/Dispatcher';
|
import Dispatcher from './monitors/Dispatcher';
|
||||||
import TopButtons from '../components/TopButtons';
|
import TopButtons from '../components/TopButtons';
|
||||||
import BottomButtons from '../components/BottomButtons';
|
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() {
|
render() {
|
||||||
const {
|
const {
|
||||||
monitor,
|
monitor,
|
||||||
|
@ -51,17 +54,7 @@ class Actions extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions.propTypes = {
|
const mapStateToProps = (state: StoreState) => {
|
||||||
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 instances = state.instances;
|
const instances = state.instances;
|
||||||
const id = getActiveInstance(instances);
|
const id = getActiveInstance(instances);
|
||||||
return {
|
return {
|
||||||
|
@ -73,13 +66,11 @@ function mapStateToProps(state) {
|
||||||
sliderIsOpen: state.monitor.sliderIsOpen,
|
sliderIsOpen: state.monitor.sliderIsOpen,
|
||||||
reports: state.reports.data,
|
reports: state.reports.data,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return {
|
|
||||||
liftedDispatch: bindActionCreators(liftedDispatchAction, dispatch),
|
|
||||||
getReport: bindActionCreators(getReport, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Actions);
|
const actionCreators = {
|
||||||
|
liftedDispatch: liftedDispatchAction,
|
||||||
|
getReport,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, actionCreators)(Actions);
|
|
@ -1,14 +1,17 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { Container, Notification } from 'devui';
|
import { Container, Notification } from 'devui';
|
||||||
import { clearNotification } from '../actions';
|
import { clearNotification } from '../actions';
|
||||||
import Header from '../components/Header';
|
import Header from '../components/Header';
|
||||||
import Actions from '../containers/Actions';
|
import Actions from '../containers/Actions';
|
||||||
import Settings from '../components/Settings';
|
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() {
|
render() {
|
||||||
const { section, theme, notification } = this.props;
|
const { section, theme, notification } = this.props;
|
||||||
let body;
|
let body;
|
||||||
|
@ -37,28 +40,14 @@ class App extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
App.propTypes = {
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
section: PropTypes.string.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired,
|
|
||||||
notification: PropTypes.shape({
|
|
||||||
message: PropTypes.string,
|
|
||||||
type: PropTypes.string,
|
|
||||||
}),
|
|
||||||
clearNotification: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
section: state.section,
|
section: state.section,
|
||||||
theme: state.theme,
|
theme: state.theme,
|
||||||
notification: state.notification,
|
notification: state.notification,
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
clearNotification,
|
||||||
clearNotification: bindActionCreators(clearNotification, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
export default connect(mapStateToProps, actionCreators)(App);
|
|
@ -1,20 +1,49 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { withTheme } from 'styled-components';
|
import { withTheme } from 'styled-components';
|
||||||
|
import { LiftedAction, LiftedState } from 'redux-devtools-instrument';
|
||||||
|
import { Action } from 'redux';
|
||||||
import getMonitor from '../utils/getMonitor';
|
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 {
|
interface Props {
|
||||||
constructor(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);
|
super(props);
|
||||||
this.getMonitor(props, props.monitorState);
|
this.getMonitor(props, props.monitorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMonitor(props, skipUpdate) {
|
getMonitor(props: Props, skipUpdate?: unknown) {
|
||||||
const monitorElement = getMonitor(props);
|
const monitorElement = getMonitor(props);
|
||||||
this.monitorProps = monitorElement.props;
|
this.monitorProps = monitorElement.props;
|
||||||
this.Monitor = monitorElement.type;
|
this.Monitor = monitorElement.type;
|
||||||
|
|
||||||
const update = this.Monitor.update;
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const update = this.Monitor!.update;
|
||||||
if (update) {
|
if (update) {
|
||||||
let newMonitorState;
|
let newMonitorState;
|
||||||
const monitorState = props.monitorState;
|
const monitorState = props.monitorState;
|
||||||
|
@ -24,7 +53,11 @@ class DevTools extends Component {
|
||||||
) {
|
) {
|
||||||
newMonitorState = monitorState;
|
newMonitorState = monitorState;
|
||||||
} else {
|
} else {
|
||||||
newMonitorState = update(this.monitorProps, undefined, {});
|
newMonitorState = update(
|
||||||
|
this.monitorProps,
|
||||||
|
undefined,
|
||||||
|
{} as Action<unknown>
|
||||||
|
);
|
||||||
if (newMonitorState !== monitorState) {
|
if (newMonitorState !== monitorState) {
|
||||||
this.preventRender = true;
|
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);
|
if (nextProps.monitor !== this.props.monitor) this.getMonitor(nextProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return (
|
return (
|
||||||
nextProps.monitor !== this.props.monitor ||
|
nextProps.monitor !== this.props.monitor ||
|
||||||
nextProps.liftedState !== this.props.liftedState ||
|
nextProps.liftedState !== this.props.liftedState ||
|
||||||
nextProps.monitorState !== this.props.liftedState ||
|
nextProps.monitorState !== this.props.monitorState ||
|
||||||
nextProps.features !== this.props.features ||
|
nextProps.features !== this.props.features ||
|
||||||
nextProps.theme.scheme !== this.props.theme.scheme
|
nextProps.theme.scheme !== this.props.theme.scheme
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch = (action) => {
|
dispatch = (
|
||||||
|
action: LiftedAction<unknown, Action<unknown>, unknown> | InitMonitorAction
|
||||||
|
) => {
|
||||||
this.props.dispatch(action);
|
this.props.dispatch(action);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,9 +101,10 @@ class DevTools extends Component {
|
||||||
...this.props.liftedState,
|
...this.props.liftedState,
|
||||||
monitorState: this.props.monitorState,
|
monitorState: this.props.monitorState,
|
||||||
};
|
};
|
||||||
|
const MonitorAsAny = this.Monitor as any;
|
||||||
return (
|
return (
|
||||||
<div className={`monitor monitor-${this.props.monitor}`}>
|
<div className={`monitor monitor-${this.props.monitor}`}>
|
||||||
<this.Monitor
|
<MonitorAsAny
|
||||||
{...liftedState}
|
{...liftedState}
|
||||||
{...this.monitorProps}
|
{...this.monitorProps}
|
||||||
features={this.props.features}
|
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);
|
export default withTheme(DevTools);
|
|
@ -1,25 +1,27 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import ChartMonitor from 'redux-devtools-chart-monitor';
|
import ChartMonitor from 'redux-devtools-chart-monitor';
|
||||||
|
import { NodeWithId } from 'd3-state-visualizer';
|
||||||
import { selectMonitorWithState } from '../../actions';
|
import { selectMonitorWithState } from '../../actions';
|
||||||
|
|
||||||
export function getPath(obj, inspectedStatePath) {
|
export function getPath(obj: NodeWithId, inspectedStatePath: string[]) {
|
||||||
const parent = obj.parent;
|
const parent = obj.parent;
|
||||||
if (!parent) return;
|
if (!parent) return;
|
||||||
getPath(parent, inspectedStatePath);
|
getPath(parent, inspectedStatePath);
|
||||||
let name = obj.name;
|
let name = obj.name;
|
||||||
const item = name.match(/.+\[(\d+)]/);
|
const item = /.+\[(\d+)]/.exec(name);
|
||||||
if (item) name = item[1];
|
if (item) name = item[1];
|
||||||
inspectedStatePath.push(name);
|
inspectedStatePath.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChartMonitorWrapper extends Component {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
|
type Props = DispatchProps;
|
||||||
|
|
||||||
|
class ChartMonitorWrapper extends Component<Props> {
|
||||||
static update = ChartMonitor.update;
|
static update = ChartMonitor.update;
|
||||||
|
|
||||||
onClickText = (data) => {
|
onClickText = (data: NodeWithId) => {
|
||||||
const inspectedStatePath = [];
|
const inspectedStatePath: string[] = [];
|
||||||
getPath(data, inspectedStatePath);
|
getPath(data, inspectedStatePath);
|
||||||
this.props.selectMonitorWithState('InspectorMonitor', {
|
this.props.selectMonitorWithState('InspectorMonitor', {
|
||||||
inspectedStatePath,
|
inspectedStatePath,
|
||||||
|
@ -33,6 +35,8 @@ class ChartMonitorWrapper extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
<ChartMonitor
|
<ChartMonitor
|
||||||
defaultIsVisible
|
defaultIsVisible
|
||||||
invertTheme
|
invertTheme
|
||||||
|
@ -43,17 +47,8 @@ class ChartMonitorWrapper extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChartMonitorWrapper.propTypes = {
|
const actionCreators = {
|
||||||
selectMonitorWithState: PropTypes.func.isRequired,
|
selectMonitorWithState: selectMonitorWithState,
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
export default connect(null, actionCreators)(ChartMonitorWrapper);
|
||||||
return {
|
|
||||||
selectMonitorWithState: bindActionCreators(
|
|
||||||
selectMonitorWithState,
|
|
||||||
dispatch
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(ChartMonitorWrapper);
|
|
|
@ -1,12 +1,11 @@
|
||||||
// Based on https://github.com/YoruNoHikage/redux-devtools-dispatch
|
// Based on https://github.com/YoruNoHikage/redux-devtools-dispatch
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Button, Select, Editor, Toolbar } from 'devui';
|
import { Button, Select, Editor, Toolbar } from 'devui';
|
||||||
import { bindActionCreators } from 'redux';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { dispatchRemotely } from '../../actions';
|
import { dispatchRemotely } from '../../actions';
|
||||||
|
import { Options } from '../../reducers/instances';
|
||||||
|
|
||||||
export const DispatcherContainer = styled.div`
|
export const DispatcherContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -47,13 +46,22 @@ export const ActionContainer = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class Dispatcher extends Component {
|
type DispatchProps = ResolveThunks<typeof actionCreators>;
|
||||||
static propTypes = {
|
interface OwnProps {
|
||||||
options: PropTypes.object.isRequired,
|
options: Options;
|
||||||
dispatch: PropTypes.func.isRequired,
|
}
|
||||||
};
|
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',
|
selected: 'default',
|
||||||
customAction:
|
customAction:
|
||||||
this.props.options.lib === 'redux' ? "{\n type: ''\n}" : 'this.',
|
this.props.options.lib === 'redux' ? "{\n type: ''\n}" : 'this.',
|
||||||
|
@ -62,7 +70,7 @@ class Dispatcher extends Component {
|
||||||
changed: false,
|
changed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||||
if (
|
if (
|
||||||
this.state.selected !== 'default' &&
|
this.state.selected !== 'default' &&
|
||||||
!nextProps.options.actionCreators
|
!nextProps.options.actionCreators
|
||||||
|
@ -74,14 +82,14 @@ class Dispatcher extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||||
return (
|
return (
|
||||||
nextState !== this.state ||
|
nextState !== this.state ||
|
||||||
nextProps.options.actionCreators !== this.props.options.actionCreators
|
nextProps.options.actionCreators !== this.props.options.actionCreators
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectActionCreator = (selected) => {
|
selectActionCreator = (selected: 'default' | 'actions-help' | number) => {
|
||||||
if (selected === 'actions-help') {
|
if (selected === 'actions-help') {
|
||||||
window.open(
|
window.open(
|
||||||
'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/' +
|
'https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/' +
|
||||||
|
@ -90,14 +98,14 @@ class Dispatcher extends Component {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const args = [];
|
const args: string[] = [];
|
||||||
if (selected !== 'default') {
|
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 });
|
this.setState({ selected, args, rest: '[]', changed: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleArg = (argIndex) => (value) => {
|
handleArg = (argIndex: number) => (value: string) => {
|
||||||
const args = [
|
const args = [
|
||||||
...this.state.args.slice(0, argIndex),
|
...this.state.args.slice(0, argIndex),
|
||||||
value || undefined,
|
value || undefined,
|
||||||
|
@ -106,26 +114,26 @@ class Dispatcher extends Component {
|
||||||
this.setState({ args, changed: true });
|
this.setState({ args, changed: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleRest = (rest) => {
|
handleRest = (rest: string) => {
|
||||||
this.setState({ rest, changed: true });
|
this.setState({ rest, changed: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCustomAction = (customAction) => {
|
handleCustomAction = (customAction: string) => {
|
||||||
this.setState({ customAction, changed: true });
|
this.setState({ customAction, changed: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatchAction = () => {
|
dispatchAction = () => {
|
||||||
const { selected, customAction, args, rest } = this.state;
|
const { selected, customAction, args, rest } = this.state;
|
||||||
|
|
||||||
if (this.state.selected !== 'default') {
|
if (selected !== 'default') {
|
||||||
// remove trailing `undefined` arguments
|
// remove trailing `undefined` arguments
|
||||||
let i = args.length - 1;
|
let i = args.length - 1;
|
||||||
while (i >= 0 && typeof args[i] === 'undefined') {
|
while (i >= 0 && typeof args[i] === 'undefined') {
|
||||||
args.pop(i);
|
args.pop();
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
name: this.props.options.actionCreators[selected].name,
|
name: this.props.options.actionCreators![selected].name,
|
||||||
selected,
|
selected,
|
||||||
args,
|
args,
|
||||||
rest,
|
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) {
|
if (actionCreators && actionCreators.length > 0) {
|
||||||
options = options.concat(
|
options = options.concat(
|
||||||
actionCreators.map(({ name, args }, i) => ({
|
actionCreators.map(({ name, args }, i) => ({
|
||||||
|
@ -208,10 +218,8 @@ class Dispatcher extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const actionCreators = {
|
||||||
return {
|
dispatch: dispatchRemotely,
|
||||||
dispatch: bindActionCreators(dispatchRemotely, dispatch),
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(null, mapDispatchToProps)(Dispatcher);
|
export default connect(null, actionCreators)(Dispatcher);
|
|
@ -1,18 +1,28 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component, RefCallback } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { withTheme } from 'styled-components';
|
import { withTheme } from 'styled-components';
|
||||||
import { tree } from 'd3-state-visualizer';
|
import { InputOptions, NodeWithId, tree } from 'd3-state-visualizer';
|
||||||
import { getPath } from '../ChartMonitorWrapper';
|
import { getPath } from '../ChartMonitorWrapper';
|
||||||
import { updateMonitorState } from '../../../actions';
|
import { updateMonitorState } from '../../../actions';
|
||||||
|
import { ThemeFromProvider } from 'devui';
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '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() {
|
shouldComponentUpdate() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -21,28 +31,30 @@ class ChartTab extends Component {
|
||||||
this.createChart(this.props);
|
this.createChart(this.props);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||||
if (
|
if (
|
||||||
this.props.theme.scheme !== nextProps.theme.scheme ||
|
this.props.theme.scheme !== nextProps.theme.scheme ||
|
||||||
nextProps.theme.light !== this.props.theme.light
|
nextProps.theme.light !== this.props.theme.light
|
||||||
) {
|
) {
|
||||||
this.node.innerHTML = '';
|
this.node!.innerHTML = '';
|
||||||
this.createChart(nextProps);
|
this.createChart(nextProps);
|
||||||
} else if (nextProps.data !== this.props.data) {
|
} 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;
|
this.node = node;
|
||||||
};
|
};
|
||||||
|
|
||||||
createChart(props) {
|
createChart(props: Props) {
|
||||||
this.renderChart = tree(this.node, this.getChartTheme(props.theme));
|
this.renderChart = tree(this.node!, this.getChartTheme(props.theme));
|
||||||
this.renderChart(props.data);
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
this.renderChart(props.data as {} | null | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChartTheme(theme) {
|
getChartTheme(theme: ThemeFromProvider): Partial<InputOptions> {
|
||||||
return {
|
return {
|
||||||
heightBetweenNodesCoeff: 1,
|
heightBetweenNodesCoeff: 1,
|
||||||
widthBetweenNodesCoeff: 1.3,
|
widthBetweenNodesCoeff: 1.3,
|
||||||
|
@ -60,27 +72,27 @@ class ChartTab extends Component {
|
||||||
style: {
|
style: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
node: {
|
node: ({
|
||||||
colors: {
|
colors: {
|
||||||
default: theme.base0B,
|
default: theme.base0B,
|
||||||
collapsed: theme.base0B,
|
collapsed: theme.base0B,
|
||||||
parent: theme.base0E,
|
parent: theme.base0E,
|
||||||
},
|
},
|
||||||
radius: 7,
|
radius: 7,
|
||||||
},
|
} as unknown) as string,
|
||||||
text: {
|
text: ({
|
||||||
colors: {
|
colors: {
|
||||||
default: theme.base0D,
|
default: theme.base0D,
|
||||||
hover: theme.base06,
|
hover: theme.base06,
|
||||||
},
|
},
|
||||||
},
|
} as unknown) as string,
|
||||||
},
|
},
|
||||||
onClickText: this.onClickText,
|
onClickText: this.onClickText,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickText = (data) => {
|
onClickText = (data: NodeWithId) => {
|
||||||
const inspectedStatePath = [];
|
const inspectedStatePath: string[] = [];
|
||||||
getPath(data, inspectedStatePath);
|
getPath(data, inspectedStatePath);
|
||||||
this.props.updateMonitorState({
|
this.props.updateMonitorState({
|
||||||
inspectedStatePath,
|
inspectedStatePath,
|
||||||
|
@ -93,17 +105,9 @@ class ChartTab extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChartTab.propTypes = {
|
const actionCreators = {
|
||||||
data: PropTypes.object,
|
updateMonitorState,
|
||||||
updateMonitorState: PropTypes.func.isRequired,
|
|
||||||
theme: PropTypes.object.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
const ConnectedChartTab = connect(null, actionCreators)(ChartTab);
|
||||||
return {
|
|
||||||
updateMonitorState: bindActionCreators(updateMonitorState, dispatch),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const ConnectedChartTab = connect(null, mapDispatchToProps)(ChartTab);
|
|
||||||
export default withTheme(ConnectedChartTab);
|
export default withTheme(ConnectedChartTab);
|
|
@ -2,21 +2,27 @@ import React, { Component } from 'react';
|
||||||
import { Editor } from 'devui';
|
import { Editor } from 'devui';
|
||||||
import { stringify } from 'javascript-stringify';
|
import { stringify } from 'javascript-stringify';
|
||||||
|
|
||||||
export default class RawTab extends Component {
|
interface Props {
|
||||||
constructor(props) {
|
data: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class RawTab extends Component<Props> {
|
||||||
|
value?: string | undefined;
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.stringifyData(props);
|
this.stringifyData(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return nextProps.data !== this.value;
|
return nextProps.data !== this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillUpdate(nextProps) {
|
UNSAFE_componentWillUpdate(nextProps: Props) {
|
||||||
this.stringifyData(nextProps);
|
this.stringifyData(nextProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
stringifyData(props) {
|
stringifyData(props: Props) {
|
||||||
this.value = stringify(props.data, null, 2);
|
this.value = stringify(props.data, null, 2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { connect, ResolveThunks } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { Tab, Tabs } from 'devui';
|
||||||
import { connect } from 'react-redux';
|
import { TabComponentProps } from 'redux-devtools-inspector-monitor';
|
||||||
import { Tabs } from 'devui';
|
import { Action } from 'redux';
|
||||||
import StateTree from 'redux-devtools-inspector-monitor/lib/tabs/StateTab';
|
import StateTree from 'redux-devtools-inspector-monitor/lib/tabs/StateTab';
|
||||||
import ActionTree from 'redux-devtools-inspector-monitor/lib/tabs/ActionTab';
|
import ActionTree from 'redux-devtools-inspector-monitor/lib/tabs/ActionTab';
|
||||||
import DiffTree from 'redux-devtools-inspector-monitor/lib/tabs/DiffTab';
|
import DiffTree from 'redux-devtools-inspector-monitor/lib/tabs/DiffTab';
|
||||||
|
@ -10,14 +10,24 @@ import { selectMonitorTab } from '../../../actions';
|
||||||
import RawTab from './RawTab';
|
import RawTab from './RawTab';
|
||||||
import ChartTab from './ChartTab';
|
import ChartTab from './ChartTab';
|
||||||
import VisualDiffTab from './VisualDiffTab';
|
import VisualDiffTab from './VisualDiffTab';
|
||||||
|
import { StoreState } from '../../../reducers';
|
||||||
|
import { Delta } from 'jsondiffpatch';
|
||||||
|
|
||||||
class SubTabs extends Component {
|
type StateProps = ReturnType<typeof mapStateToProps>;
|
||||||
constructor(props) {
|
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);
|
super(props);
|
||||||
this.updateTabs(props);
|
this.updateTabs(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||||
if (nextProps.parentTab !== this.props.parentTab) {
|
if (nextProps.parentTab !== this.props.parentTab) {
|
||||||
this.updateTabs(nextProps);
|
this.updateTabs(nextProps);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +44,7 @@ class SubTabs extends Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateTabs(props) {
|
updateTabs(props: Props) {
|
||||||
const parentTab = props.parentTab;
|
const parentTab = props.parentTab;
|
||||||
|
|
||||||
if (parentTab === 'Diff') {
|
if (parentTab === 'Diff') {
|
||||||
|
@ -47,7 +57,7 @@ class SubTabs extends Component {
|
||||||
{
|
{
|
||||||
name: 'Raw',
|
name: 'Raw',
|
||||||
component: VisualDiffTab,
|
component: VisualDiffTab,
|
||||||
selector: this.selector,
|
selector: this.selector as () => { data?: Delta },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return;
|
return;
|
||||||
|
@ -79,7 +89,7 @@ class SubTabs extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
tabs={this.tabs}
|
tabs={this.tabs! as any}
|
||||||
selected={selected || 'Tree'}
|
selected={selected || 'Tree'}
|
||||||
onClick={this.props.selectMonitorTab}
|
onClick={this.props.selectMonitorTab}
|
||||||
/>
|
/>
|
||||||
|
@ -87,26 +97,13 @@ class SubTabs extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SubTabs.propTypes = {
|
const mapStateToProps = (state: StoreState) => ({
|
||||||
selected: PropTypes.string,
|
parentTab: state.monitor.monitorState!.tabName,
|
||||||
parentTab: PropTypes.string,
|
selected: state.monitor.monitorState!.subTabName,
|
||||||
selectMonitorTab: PropTypes.func.isRequired,
|
});
|
||||||
action: PropTypes.object,
|
|
||||||
delta: PropTypes.object,
|
const actionCreators = {
|
||||||
nextState: PropTypes.object,
|
selectMonitorTab,
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
export default connect(mapStateToProps, actionCreators)(SubTabs);
|
||||||
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);
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { Delta, formatters } from 'jsondiffpatch';
|
||||||
import { formatters } from 'jsondiffpatch';
|
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { effects } from 'devui';
|
import { effects } from 'devui';
|
||||||
|
|
||||||
|
@ -218,22 +217,22 @@ export const StyledContainer = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default class VisualDiffTab extends Component {
|
interface Props {
|
||||||
shouldComponentUpdate(nextProps) {
|
data?: Delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class VisualDiffTab extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return this.props.data !== nextProps.data;
|
return this.props.data !== nextProps.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let __html;
|
let __html: string | undefined;
|
||||||
const data = this.props.data;
|
const data = this.props.data;
|
||||||
if (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 React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import InspectorMonitor, { Tab } from 'redux-devtools-inspector-monitor';
|
||||||
import InspectorMonitor from 'redux-devtools-inspector-monitor';
|
|
||||||
import TraceTab from 'redux-devtools-inspector-monitor-trace-tab';
|
import TraceTab from 'redux-devtools-inspector-monitor-trace-tab';
|
||||||
import TestTab from 'redux-devtools-inspector-monitor-test-tab';
|
import TestTab from 'redux-devtools-inspector-monitor-test-tab';
|
||||||
import { DATA_TYPE_KEY } from '../../../constants/dataTypes';
|
import { DATA_TYPE_KEY } from '../../../constants/dataTypes';
|
||||||
import SubTabs from './SubTabs';
|
import SubTabs from './SubTabs';
|
||||||
|
import { Action } from 'redux';
|
||||||
|
|
||||||
const DEFAULT_TABS = [
|
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;
|
static update = InspectorMonitor.update;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { features, ...rest } = this.props;
|
const { features, ...rest } = this.props;
|
||||||
let tabs;
|
let tabs: () => Tab<unknown, Action<unknown>>[];
|
||||||
if (features && features.test) {
|
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 {
|
} else {
|
||||||
tabs = () => DEFAULT_TABS;
|
tabs = () => DEFAULT_TABS as Tab<unknown, Action<unknown>>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InspectorMonitor
|
<InspectorMonitor
|
||||||
dataTypeKey={DATA_TYPE_KEY}
|
dataTypeKey={DATA_TYPE_KEY}
|
||||||
shouldPersistState={false}
|
|
||||||
invertTheme={false}
|
invertTheme={false}
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
hideActionButtons={!features.skip}
|
hideActionButtons={!features!.skip}
|
||||||
hideMainButtons
|
hideMainButtons
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
|
@ -51,8 +64,4 @@ class InspectorWrapper extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InspectorWrapper.propTypes = {
|
|
||||||
features: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default InspectorWrapper;
|
export default InspectorWrapper;
|
|
@ -1,7 +1,10 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import styled, { withTheme } from 'styled-components';
|
import styled, { withTheme } from 'styled-components';
|
||||||
import SliderMonitor from 'redux-devtools-slider-monitor';
|
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`
|
const SliderWrapper = styled.div`
|
||||||
border-color: ${(props) => props.theme.base02};
|
border-color: ${(props) => props.theme.base02};
|
||||||
|
@ -9,8 +12,14 @@ const SliderWrapper = styled.div`
|
||||||
border-width: 1px 0;
|
border-width: 1px 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class Slider extends Component {
|
interface Props {
|
||||||
shouldComponentUpdate(nextProps) {
|
liftedState: State;
|
||||||
|
dispatch: (action: LiftedAction<unknown, Action<unknown>, unknown>) => void;
|
||||||
|
theme: ThemeFromProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Slider extends Component<Props> {
|
||||||
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
return (
|
return (
|
||||||
nextProps.liftedState !== this.props.liftedState ||
|
nextProps.liftedState !== this.props.liftedState ||
|
||||||
nextProps.theme.scheme !== this.props.theme.scheme
|
nextProps.theme.scheme !== this.props.theme.scheme
|
||||||
|
@ -21,6 +30,8 @@ class Slider extends Component {
|
||||||
<SliderWrapper>
|
<SliderWrapper>
|
||||||
<SliderMonitor
|
<SliderMonitor
|
||||||
{...this.props.liftedState}
|
{...this.props.liftedState}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
dispatch={this.props.dispatch}
|
dispatch={this.props.dispatch}
|
||||||
theme={this.props.theme}
|
theme={this.props.theme}
|
||||||
hideResetButton
|
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);
|
export default withTheme(Slider);
|
|
@ -1,18 +1,27 @@
|
||||||
import 'devui/lib/presets';
|
import 'devui/lib/presets';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { Store } from 'redux';
|
||||||
import configureStore from './store/configureStore';
|
import configureStore from './store/configureStore';
|
||||||
import { CONNECT_REQUEST } from './constants/socketActionTypes';
|
import { CONNECT_REQUEST } from './constants/socketActionTypes';
|
||||||
import App from './containers/App';
|
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() {
|
UNSAFE_componentWillMount() {
|
||||||
configureStore((store, preloadedState) => {
|
configureStore((store, preloadedState) => {
|
||||||
this.store = store;
|
this.store = store;
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: CONNECT_REQUEST,
|
type: CONNECT_REQUEST,
|
||||||
options: preloadedState.connection || this.props.socketOptions,
|
options: (preloadedState!.connection ||
|
||||||
|
this.props.socketOptions) as ConnectionOptions,
|
||||||
});
|
});
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
});
|
});
|
||||||
|
@ -20,21 +29,13 @@ class Root extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.store) return null;
|
if (!this.store) return null;
|
||||||
|
const AppAsAny = App as any;
|
||||||
return (
|
return (
|
||||||
<Provider store={this.store}>
|
<Provider store={this.store}>
|
||||||
<App {...this.props} />
|
<AppAsAny {...this.props} />
|
||||||
</Provider>
|
</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;
|
export default Root;
|
|
@ -1,5 +1,6 @@
|
||||||
import socketCluster from 'socketcluster-client';
|
import socketCluster, { SCClientSocket } from 'socketcluster-client';
|
||||||
import { stringify } from 'jsan';
|
import { stringify } from 'jsan';
|
||||||
|
import { Dispatch, MiddlewareAPI } from 'redux';
|
||||||
import socketOptions from '../constants/socketOptions';
|
import socketOptions from '../constants/socketOptions';
|
||||||
import * as actions from '../constants/socketActionTypes';
|
import * as actions from '../constants/socketActionTypes';
|
||||||
import { getActiveInstance } from '../reducers/instances';
|
import { getActiveInstance } from '../reducers/instances';
|
||||||
|
@ -12,22 +13,37 @@ import {
|
||||||
GET_REPORT_ERROR,
|
GET_REPORT_ERROR,
|
||||||
GET_REPORT_SUCCESS,
|
GET_REPORT_SUCCESS,
|
||||||
} from '../constants/actionTypes';
|
} 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 { nonReduxDispatch } from '../utils/monitorActions';
|
||||||
|
import { StoreState } from '../reducers';
|
||||||
|
|
||||||
let socket;
|
let socket: SCClientSocket;
|
||||||
let store;
|
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 });
|
socket.emit(id ? 'sc-' + id : 'respond', { type, action, state, instanceId });
|
||||||
}
|
}
|
||||||
|
|
||||||
function startMonitoring(channel) {
|
function startMonitoring(channel: string) {
|
||||||
if (channel !== store.getState().socket.baseChannel) return;
|
if (channel !== store.getState().socket.baseChannel) return;
|
||||||
store.dispatch({ type: actions.EMIT, message: 'START' });
|
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 instances = store.getState().instances;
|
||||||
const instanceId = getActiveInstance(instances);
|
const instanceId = getActiveInstance(instances);
|
||||||
const id = !toAll && instances.options[instanceId].connectionId;
|
const id = !toAll && instances.options[instanceId].connectionId;
|
||||||
|
@ -39,7 +55,7 @@ function dispatchRemoteAction({ message, action, state, toAll }) {
|
||||||
store,
|
store,
|
||||||
message,
|
message,
|
||||||
instanceId,
|
instanceId,
|
||||||
action,
|
action as DispatchAction,
|
||||||
state,
|
state,
|
||||||
instances
|
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') {
|
if (request.type === 'DISCONNECTED') {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: REMOVE_INSTANCE,
|
type: REMOVE_INSTANCE,
|
||||||
|
@ -68,7 +109,9 @@ function monitoring(request) {
|
||||||
|
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: UPDATE_STATE,
|
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;
|
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);
|
const channel = socket.subscribe(channelName);
|
||||||
if (subscription === UPDATE_STATE) channel.watch(monitoring);
|
if (subscription === UPDATE_STATE) channel.watch(monitoring);
|
||||||
else {
|
else {
|
||||||
const watcher = (request) => {
|
const watcher = (request: UpdateReportsRequest) => {
|
||||||
store.dispatch({ type: subscription, request });
|
store.dispatch({ type: subscription, request });
|
||||||
};
|
};
|
||||||
channel.watch(watcher);
|
channel.watch(watcher);
|
||||||
|
@ -150,7 +196,7 @@ function connect() {
|
||||||
socket = socketCluster.create(
|
socket = socketCluster.create(
|
||||||
connection.type === 'remotedev' ? socketOptions : connection.options
|
connection.type === 'remotedev' ? socketOptions : connection.options
|
||||||
);
|
);
|
||||||
handleConnection(store);
|
handleConnection();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
store.dispatch({ type: actions.CONNECT_ERROR, error });
|
store.dispatch({ type: actions.CONNECT_ERROR, error });
|
||||||
store.dispatch(showNotification(error.message || error));
|
store.dispatch(showNotification(error.message || error));
|
||||||
|
@ -163,7 +209,7 @@ function disconnect() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function login() {
|
function login() {
|
||||||
socket.emit('login', {}, (error, baseChannel) => {
|
socket.emit('login', {}, (error: Error, baseChannel: string) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
store.dispatch({ type: actions.AUTH_ERROR, error });
|
store.dispatch({ type: actions.AUTH_ERROR, error });
|
||||||
return;
|
return;
|
||||||
|
@ -182,24 +228,28 @@ function login() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReport(reportId) {
|
function getReport(reportId: unknown) {
|
||||||
socket.emit('getReport', reportId, (error, data) => {
|
socket.emit(
|
||||||
|
'getReport',
|
||||||
|
reportId,
|
||||||
|
(error: Error, data: { payload: string }) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
store.dispatch({ type: GET_REPORT_ERROR, error });
|
store.dispatch({ type: GET_REPORT_ERROR, error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
store.dispatch({ type: GET_REPORT_SUCCESS, data });
|
store.dispatch({ type: GET_REPORT_SUCCESS, data });
|
||||||
store.dispatch(importState(data.payload));
|
store.dispatch(importState(data.payload));
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function api(inStore) {
|
export default function api(
|
||||||
store = inStore;
|
inStore: MiddlewareAPI<Dispatch<StoreAction>, StoreState>
|
||||||
return (next) => (action) => {
|
|
||||||
const result = next(action);
|
|
||||||
switch (
|
|
||||||
action.type // eslint-disable-line default-case
|
|
||||||
) {
|
) {
|
||||||
|
store = inStore;
|
||||||
|
return (next: Dispatch<StoreAction>) => (action: StoreAction) => {
|
||||||
|
const result = next(action);
|
||||||
|
switch (action.type) {
|
||||||
case actions.CONNECT_REQUEST:
|
case actions.CONNECT_REQUEST:
|
||||||
connect();
|
connect();
|
||||||
break;
|
break;
|
|
@ -1,14 +1,17 @@
|
||||||
import stringifyJSON from '../utils/stringifyJSON';
|
import stringifyJSON from '../utils/stringifyJSON';
|
||||||
import { UPDATE_STATE, LIFTED_ACTION, EXPORT } from '../constants/actionTypes';
|
import { UPDATE_STATE, LIFTED_ACTION, EXPORT } from '../constants/actionTypes';
|
||||||
import { getActiveInstance } from '../reducers/instances';
|
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 blob = new Blob([state], { type: 'octet/stream' });
|
||||||
const href = window.URL.createObjectURL(blob);
|
const href = window.URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.style = 'display: none';
|
a.style.display = 'none';
|
||||||
a.download = 'state.json';
|
a.download = 'state.json';
|
||||||
a.href = href;
|
a.href = href;
|
||||||
document.body.appendChild(a);
|
document.body.appendChild(a);
|
||||||
|
@ -19,15 +22,17 @@ function download(state) {
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportState = (store) => (next) => (action) => {
|
const exportState = (
|
||||||
|
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>
|
||||||
|
) => (next: Dispatch<StoreAction>) => (action: StoreAction) => {
|
||||||
const result = next(action);
|
const result = next(action);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
toExport &&
|
toExport &&
|
||||||
action.type === UPDATE_STATE &&
|
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;
|
const id = request.instanceId || request.id;
|
||||||
if (id === toExport) {
|
if (id === toExport) {
|
||||||
toExport = undefined;
|
toExport = undefined;
|
||||||
|
@ -35,7 +40,7 @@ const exportState = (store) => (next) => (action) => {
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
{
|
{
|
||||||
payload: request.payload,
|
payload: request.payload,
|
||||||
preloadedState: request.committedState,
|
preloadedState: (request as ExportRequest).committedState,
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
'\t'
|
'\t'
|
|
@ -1,11 +1,22 @@
|
||||||
import { RECONNECT } from '../constants/socketActionTypes';
|
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(
|
export default function connection(
|
||||||
state = {
|
state: ConnectionState = {
|
||||||
options: { hostname: 'localhost', port: 8000, secure: false },
|
options: { hostname: 'localhost', port: 8000, secure: false },
|
||||||
type: 'remotedev',
|
type: 'remotedev',
|
||||||
},
|
},
|
||||||
action
|
action: StoreAction
|
||||||
) {
|
) {
|
||||||
if (action.type === RECONNECT) {
|
if (action.type === RECONNECT) {
|
||||||
const { type, ...options } = action.options;
|
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 {
|
import {
|
||||||
UPDATE_STATE,
|
UPDATE_STATE,
|
||||||
SET_STATE,
|
SET_STATE,
|
||||||
|
@ -10,8 +12,60 @@ import {
|
||||||
import { DISCONNECTED } from '../constants/socketActionTypes';
|
import { DISCONNECTED } from '../constants/socketActionTypes';
|
||||||
import parseJSON from '../utils/parseJSON';
|
import parseJSON from '../utils/parseJSON';
|
||||||
import { recompute } from '../utils/updateState';
|
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,
|
selected: null,
|
||||||
current: 'default',
|
current: 'default',
|
||||||
sync: false,
|
sync: false,
|
||||||
|
@ -29,35 +83,42 @@ export const initialState = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateState(state, request, id, serialize) {
|
function updateState(
|
||||||
let payload = request.payload;
|
state: { [id: string]: State },
|
||||||
|
request: Request,
|
||||||
|
id: string,
|
||||||
|
serialize: boolean | undefined
|
||||||
|
) {
|
||||||
|
let payload: State = request.payload as State;
|
||||||
const actionsById = request.actionsById;
|
const actionsById = request.actionsById;
|
||||||
if (actionsById) {
|
if (actionsById) {
|
||||||
payload = {
|
payload = {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
...payload,
|
...payload,
|
||||||
actionsById: parseJSON(actionsById, serialize),
|
actionsById: parseJSON(actionsById, serialize),
|
||||||
computedStates: parseJSON(request.computedStates, serialize),
|
computedStates: parseJSON(request.computedStates, serialize),
|
||||||
};
|
} as State;
|
||||||
if (request.type === 'STATE' && request.committedState) {
|
if (request.type === 'STATE' && request.committedState) {
|
||||||
payload.committedState = payload.computedStates[0].state;
|
payload.committedState = payload.computedStates[0].state;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
payload = parseJSON(payload, serialize);
|
payload = parseJSON((payload as unknown) as string, serialize) as State;
|
||||||
}
|
}
|
||||||
|
|
||||||
let newState;
|
let newState;
|
||||||
const liftedState = state[id] || state.default;
|
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) {
|
switch (request.type) {
|
||||||
case 'INIT':
|
case 'INIT':
|
||||||
newState = recompute(state.default, payload, {
|
newState = recompute(state.default, payload, {
|
||||||
action: { type: '@@INIT' },
|
action: { type: '@@INIT' },
|
||||||
timestamp: action.timestamp || Date.now(),
|
timestamp: (action as { timestamp?: number }).timestamp || Date.now(),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'ACTION': {
|
case 'ACTION': {
|
||||||
let isExcess = request.isExcess;
|
const isExcess = request.isExcess;
|
||||||
const nextActionId = request.nextActionId || liftedState.nextActionId + 1;
|
const nextActionId = request.nextActionId || liftedState.nextActionId + 1;
|
||||||
const maxAge = request.maxAge;
|
const maxAge = request.maxAge;
|
||||||
if (Array.isArray(action)) {
|
if (Array.isArray(action)) {
|
||||||
|
@ -66,7 +127,7 @@ function updateState(state, request, id, serialize) {
|
||||||
for (let i = 0; i < action.length; i++) {
|
for (let i = 0; i < action.length; i++) {
|
||||||
newState = recompute(
|
newState = recompute(
|
||||||
newState,
|
newState,
|
||||||
request.batched ? payload : payload[i],
|
request.batched ? payload : ((payload as unknown) as State[])[i],
|
||||||
action[i],
|
action[i],
|
||||||
newState.nextActionId + 1,
|
newState.nextActionId + 1,
|
||||||
maxAge,
|
maxAge,
|
||||||
|
@ -148,7 +209,10 @@ function updateState(state, request, id, serialize) {
|
||||||
return { ...state, [id]: newState };
|
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') {
|
if (action.type === 'JUMP_TO_STATE' || action.type === 'JUMP_TO_ACTION') {
|
||||||
const id = state.selected || state.current;
|
const id = state.selected || state.current;
|
||||||
const liftedState = state.states[id];
|
const liftedState = state.states[id];
|
||||||
|
@ -167,7 +231,7 @@ export function dispatchAction(state, { action }) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeState(state, connectionId) {
|
function removeState(state: InstancesState, connectionId: string) {
|
||||||
const instanceIds = state.connections[connectionId];
|
const instanceIds = state.connections[connectionId];
|
||||||
if (!instanceIds) return state;
|
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 lib;
|
||||||
let actionCreators;
|
let actionCreators;
|
||||||
let creators = libConfig.actionCreators || action;
|
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) {
|
switch (action.type) {
|
||||||
case UPDATE_STATE: {
|
case UPDATE_STATE: {
|
||||||
const { request } = action;
|
const { request } = action;
|
||||||
|
@ -293,7 +364,7 @@ export default function instances(state = initialState, action) {
|
||||||
...state,
|
...state,
|
||||||
states: {
|
states: {
|
||||||
...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: InstancesState) =>
|
||||||
export const getActiveInstance = (instances) =>
|
|
||||||
instances.selected || instances.current;
|
instances.selected || instances.current;
|
||||||
/* eslint-enable */
|
|
|
@ -5,28 +5,50 @@ import {
|
||||||
TOGGLE_SLIDER,
|
TOGGLE_SLIDER,
|
||||||
TOGGLE_DISPATCHER,
|
TOGGLE_DISPATCHER,
|
||||||
} from '../constants/actionTypes';
|
} 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',
|
selected: 'InspectorMonitor',
|
||||||
monitorState: undefined,
|
monitorState: undefined,
|
||||||
sliderIsOpen: true,
|
sliderIsOpen: true,
|
||||||
dispatcherIsOpen: false,
|
dispatcherIsOpen: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function dispatchMonitorAction(state, action) {
|
export function dispatchMonitorAction(
|
||||||
|
state: MonitorState,
|
||||||
|
action: MonitorActionAction
|
||||||
|
): MonitorState {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
monitorState:
|
monitorState: (action.action.newMonitorState ||
|
||||||
action.action.newMonitorState ||
|
|
||||||
action.monitorReducer(
|
action.monitorReducer(
|
||||||
action.monitorProps,
|
action.monitorProps,
|
||||||
state.monitorState,
|
state.monitorState,
|
||||||
action.action
|
action.action
|
||||||
),
|
)) as MonitorStateMonitorState,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function monitor(state = initialState, action) {
|
export default function monitor(
|
||||||
|
state = initialState,
|
||||||
|
action: StoreAction
|
||||||
|
): MonitorState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case MONITOR_ACTION:
|
case MONITOR_ACTION:
|
||||||
return dispatchMonitorAction(state, action);
|
return dispatchMonitorAction(state, action);
|
||||||
|
@ -45,7 +67,7 @@ export default function monitor(state = initialState, action) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case UPDATE_MONITOR_STATE: {
|
case UPDATE_MONITOR_STATE: {
|
||||||
let inspectedStatePath = state.monitorState.inspectedStatePath;
|
let inspectedStatePath = state.monitorState!.inspectedStatePath!;
|
||||||
if (action.nextState.inspectedStatePath) {
|
if (action.nextState.inspectedStatePath) {
|
||||||
inspectedStatePath = [
|
inspectedStatePath = [
|
||||||
...inspectedStatePath.slice(0, -1),
|
...inspectedStatePath.slice(0, -1),
|
|
@ -4,8 +4,18 @@ import {
|
||||||
LIFTED_ACTION,
|
LIFTED_ACTION,
|
||||||
ERROR,
|
ERROR,
|
||||||
} from '../constants/actionTypes';
|
} 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) {
|
switch (action.type) {
|
||||||
case SHOW_NOTIFICATION:
|
case SHOW_NOTIFICATION:
|
||||||
return action.notification;
|
return action.notification;
|
|
@ -1,12 +1,24 @@
|
||||||
import {
|
import {
|
||||||
UPDATE_REPORTS /* , GET_REPORT_SUCCESS */,
|
UPDATE_REPORTS /* , GET_REPORT_SUCCESS */,
|
||||||
} from '../constants/actionTypes';
|
} from '../constants/actionTypes';
|
||||||
|
import { StoreAction } from '../actions';
|
||||||
|
|
||||||
const initialState = {
|
export interface Data {
|
||||||
|
id: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReportsState {
|
||||||
|
data: Data[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: ReportsState = {
|
||||||
data: [],
|
data: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function reports(state = initialState, action) {
|
export default function reports(
|
||||||
|
state = initialState,
|
||||||
|
action: StoreAction
|
||||||
|
): ReportsState {
|
||||||
/* if (action.type === GET_REPORT_SUCCESS) {
|
/* if (action.type === GET_REPORT_SUCCESS) {
|
||||||
const id = action.data.id;
|
const id = action.data.id;
|
||||||
return {
|
return {
|
||||||
|
@ -19,17 +31,16 @@ export default function reports(state = initialState, action) {
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
const request = action.request;
|
const request = action.request;
|
||||||
const data = request.data;
|
|
||||||
switch (request.type) {
|
switch (request.type) {
|
||||||
case 'list':
|
case 'list':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
data,
|
data: request.data,
|
||||||
};
|
};
|
||||||
case 'add':
|
case 'add':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
data: [...state.data, data],
|
data: [...state.data, request.data],
|
||||||
};
|
};
|
||||||
case 'remove':
|
case 'remove':
|
||||||
return {
|
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 * 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,
|
id: null,
|
||||||
channels: [],
|
channels: [],
|
||||||
socketState: actions.CLOSED,
|
socketState: actions.CLOSED,
|
||||||
authState: actions.PENDING,
|
authState: actions.PENDING,
|
||||||
authToken: null,
|
|
||||||
error: undefined,
|
error: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function socket(state = initialState, action) {
|
export default function socket(
|
||||||
|
state = initialState,
|
||||||
|
action: StoreAction
|
||||||
|
): SocketState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actions.CONNECT_REQUEST: {
|
case actions.CONNECT_REQUEST: {
|
||||||
return {
|
return {
|
||||||
|
@ -39,7 +53,6 @@ export default function socket(state = initialState, action) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
authState: actions.AUTHENTICATED,
|
authState: actions.AUTHENTICATED,
|
||||||
authToken: action.authToken,
|
|
||||||
baseChannel: action.baseChannel,
|
baseChannel: action.baseChannel,
|
||||||
};
|
};
|
||||||
case actions.AUTH_ERROR:
|
case actions.AUTH_ERROR:
|
||||||
|
@ -57,13 +70,13 @@ export default function socket(state = initialState, action) {
|
||||||
case actions.SUBSCRIBE_SUCCESS:
|
case actions.SUBSCRIBE_SUCCESS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
channels: [...state.channels, action.channelName],
|
channels: [...state.channels, action.channel],
|
||||||
};
|
};
|
||||||
case actions.UNSUBSCRIBE:
|
case actions.UNSUBSCRIBE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
channels: state.channels.filter(
|
channels: state.channels.filter(
|
||||||
(channel) => channel !== action.channelName
|
(channel) => channel !== action.channel
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
case actions.DISCONNECTED:
|
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
|
// Based on https://github.com/gaearon/redux-devtools/pull/241
|
||||||
/* eslint-disable no-param-reassign */
|
/* 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.
|
// Auto-commits n-number of excess actions.
|
||||||
let excess = n;
|
let excess = n;
|
||||||
let idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1);
|
let idsToDelete = liftedState.stagedActionIds.slice(1, excess + 1);
|
|
@ -9,7 +9,7 @@ export const monitors = [
|
||||||
{ value: 'ChartMonitor', name: 'Chart' },
|
{ value: 'ChartMonitor', name: 'Chart' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function getMonitor({ monitor }) {
|
export default function getMonitor({ monitor }: { monitor: string }) {
|
||||||
switch (monitor) {
|
switch (monitor) {
|
||||||
case 'LogMonitor':
|
case 'LogMonitor':
|
||||||
return (
|
return (
|
|
@ -2,8 +2,12 @@ import difference from 'lodash/difference';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
import stringifyJSON from './stringifyJSON';
|
import stringifyJSON from './stringifyJSON';
|
||||||
import { SET_STATE } from '../constants/actionTypes';
|
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 {
|
return {
|
||||||
...state,
|
...state,
|
||||||
actionsById: omit(state.actionsById, state.skippedActionIds),
|
actionsById: omit(state.actionsById, state.skippedActionIds),
|
||||||
|
@ -17,12 +21,12 @@ export function sweep(state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nonReduxDispatch(
|
export function nonReduxDispatch(
|
||||||
store,
|
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
|
||||||
message,
|
message: string,
|
||||||
instanceId,
|
instanceId: string,
|
||||||
action,
|
action: DispatchAction,
|
||||||
initialState,
|
initialState: string | undefined,
|
||||||
preInstances
|
preInstances: InstancesState
|
||||||
) {
|
) {
|
||||||
const instances = preInstances || store.getState().instances;
|
const instances = preInstances || store.getState().instances;
|
||||||
const state = instances.states[instanceId];
|
const state = instances.states[instanceId];
|
|
@ -1,17 +1,17 @@
|
||||||
import jsan from 'jsan';
|
import jsan from 'jsan';
|
||||||
import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes';
|
import { DATA_TYPE_KEY, DATA_REF_KEY } from '../constants/dataTypes';
|
||||||
|
|
||||||
export function reviver(key, value) {
|
export function reviver(key: string, value: unknown) {
|
||||||
if (
|
if (
|
||||||
typeof value === 'object' &&
|
typeof value === 'object' &&
|
||||||
value !== null &&
|
value !== null &&
|
||||||
'__serializedType__' in value &&
|
'__serializedType__' in value &&
|
||||||
typeof value.data === 'object'
|
typeof (value as any).data === 'object'
|
||||||
) {
|
) {
|
||||||
const data = value.data;
|
const data = (value as any).data;
|
||||||
data[DATA_TYPE_KEY] = value.__serializedType__;
|
data[DATA_TYPE_KEY] = (value as any).__serializedType__;
|
||||||
if ('__serializedRef__' in value)
|
if ('__serializedRef__' in value)
|
||||||
data[DATA_REF_KEY] = value.__serializedRef__;
|
data[DATA_REF_KEY] = (value as any).__serializedRef__;
|
||||||
/*
|
/*
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
data.__serializedType__ = value.__serializedType__;
|
data.__serializedType__ = value.__serializedType__;
|
||||||
|
@ -26,7 +26,10 @@ export function reviver(key, value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function parseJSON(data, serialize) {
|
export default function parseJSON(
|
||||||
|
data: string | undefined,
|
||||||
|
serialize?: boolean
|
||||||
|
) {
|
||||||
if (typeof data !== 'string') return data;
|
if (typeof data !== 'string') return data;
|
||||||
try {
|
try {
|
||||||
return serialize ? jsan.parse(data, reviver) : jsan.parse(data);
|
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 commitExcessActions from './commitExcessActions';
|
||||||
|
import { State } from '../reducers/instances';
|
||||||
|
import { Action } from 'redux';
|
||||||
|
import { PerformAction } from 'redux-devtools-instrument';
|
||||||
|
|
||||||
export function recompute(
|
export function recompute(
|
||||||
previousLiftedState,
|
previousLiftedState: State,
|
||||||
storeState,
|
storeState: State,
|
||||||
action,
|
action:
|
||||||
|
| PerformAction<Action<unknown>>
|
||||||
|
| { action: Action<unknown>; timestamp?: number; stack?: string },
|
||||||
nextActionId = 1,
|
nextActionId = 1,
|
||||||
maxAge,
|
maxAge?: number,
|
||||||
isExcess
|
isExcess?: boolean
|
||||||
) {
|
) {
|
||||||
const actionId = nextActionId - 1;
|
const actionId = nextActionId - 1;
|
||||||
const liftedState = { ...previousLiftedState };
|
const liftedState = { ...previousLiftedState };
|
||||||
|
@ -19,8 +24,10 @@ export function recompute(
|
||||||
}
|
}
|
||||||
liftedState.stagedActionIds = [...liftedState.stagedActionIds, actionId];
|
liftedState.stagedActionIds = [...liftedState.stagedActionIds, actionId];
|
||||||
liftedState.actionsById = { ...liftedState.actionsById };
|
liftedState.actionsById = { ...liftedState.actionsById };
|
||||||
if (action.type === 'PERFORM_ACTION') {
|
if ((action as PerformAction<Action<unknown>>).type === 'PERFORM_ACTION') {
|
||||||
liftedState.actionsById[actionId] = action;
|
liftedState.actionsById[actionId] = action as PerformAction<
|
||||||
|
Action<unknown>
|
||||||
|
>;
|
||||||
} else {
|
} else {
|
||||||
liftedState.actionsById[actionId] = {
|
liftedState.actionsById[actionId] = {
|
||||||
action: action.action || action,
|
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 React from 'react';
|
||||||
import { render } from 'react-dom';
|
import { render } from 'react-dom';
|
||||||
import App from './src/app';
|
import App from './app';
|
||||||
|
|
||||||
render(<App />, document.getElementById('root'));
|
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 mapValues from 'lodash/mapValues';
|
||||||
|
import { PerformAction } from 'redux-devtools-instrument';
|
||||||
|
import { Action } from 'redux';
|
||||||
|
import { State } from '../app/reducers/instances';
|
||||||
|
|
||||||
export const FilterState = {
|
export const FilterState = {
|
||||||
DO_NOT_FILTER: 'DO_NOT_FILTER',
|
DO_NOT_FILTER: 'DO_NOT_FILTER',
|
||||||
|
@ -6,19 +9,25 @@ export const FilterState = {
|
||||||
WHITELIST_SPECIFIC: 'WHITELIST_SPECIFIC',
|
WHITELIST_SPECIFIC: 'WHITELIST_SPECIFIC',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function arrToRegex(v) {
|
export function arrToRegex(v: string | string[]) {
|
||||||
return typeof v === 'string' ? v : v.join('|');
|
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;
|
if (!actionsFilter) return actionsById;
|
||||||
return mapValues(actionsById, (action, id) => ({
|
return mapValues(actionsById, (action, id: number) => ({
|
||||||
...action,
|
...action,
|
||||||
action: actionsFilter(action.action, id),
|
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;
|
if (!statesFilter) return computedStates;
|
||||||
return computedStates.map((state, idx) => ({
|
return computedStates.map((state, idx) => ({
|
||||||
...state,
|
...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) {
|
if (config.actionsBlacklist || config.actionsWhitelist) {
|
||||||
return {
|
return {
|
||||||
whitelist: config.actionsWhitelist && config.actionsWhitelist.join('|'),
|
whitelist: config.actionsWhitelist && config.actionsWhitelist.join('|'),
|
||||||
|
@ -36,33 +55,53 @@ export function getLocalFilter(config) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DevToolsOptions {
|
||||||
|
filter?:
|
||||||
|
| typeof FilterState.DO_NOT_FILTER
|
||||||
|
| typeof FilterState.BLACKLIST_SPECIFIC
|
||||||
|
| typeof FilterState.WHITELIST_SPECIFIC;
|
||||||
|
whitelist?: string;
|
||||||
|
blacklist?: string;
|
||||||
|
}
|
||||||
function getDevToolsOptions() {
|
function getDevToolsOptions() {
|
||||||
return (typeof window !== 'undefined' && window.devToolsOptions) || {};
|
return (
|
||||||
|
(typeof window !== 'undefined' &&
|
||||||
|
(window as { devToolsOptions?: DevToolsOptions }).devToolsOptions) ||
|
||||||
|
{}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFiltered(action, localFilter) {
|
export function isFiltered(
|
||||||
const { type } = action.action || action;
|
action: PerformAction<Action<unknown>> | Action<unknown>,
|
||||||
|
localFilter?: LocalFilter
|
||||||
|
) {
|
||||||
|
const { type } = (action as PerformAction<Action<unknown>>).action || action;
|
||||||
const opts = getDevToolsOptions();
|
const opts = getDevToolsOptions();
|
||||||
if (
|
if (
|
||||||
(!localFilter &&
|
(!localFilter &&
|
||||||
opts.filter &&
|
opts.filter &&
|
||||||
opts.filter === FilterState.DO_NOT_FILTER) ||
|
opts.filter === FilterState.DO_NOT_FILTER) ||
|
||||||
(type && typeof type.match !== 'function')
|
(type && typeof (type as string).match !== 'function')
|
||||||
)
|
)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const { whitelist, blacklist } = localFilter || opts;
|
const { whitelist, blacklist } = localFilter || opts;
|
||||||
return (
|
return (
|
||||||
(whitelist && !type.match(whitelist)) ||
|
// eslint-disable-next-line @typescript-eslint/prefer-regexp-exec
|
||||||
(blacklist && type.match(blacklist))
|
(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;
|
if (!filters) return state;
|
||||||
|
|
||||||
const filteredStagedActionIds = [];
|
const filteredStagedActionIds: number[] = [];
|
||||||
const filteredComputedStates = [];
|
const filteredComputedStates: {
|
||||||
|
state: unknown;
|
||||||
|
error?: string | undefined;
|
||||||
|
}[] = [];
|
||||||
|
|
||||||
state.stagedActionIds.forEach((id, idx) => {
|
state.stagedActionIds.forEach((id, idx) => {
|
||||||
if (!isFiltered(state.actionsById[id], filters)) {
|
if (!isFiltered(state.actionsById[id], filters)) {
|
||||||
|
@ -79,13 +118,13 @@ export function filterStagedActions(state, filters) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function filterState(
|
export function filterState(
|
||||||
state,
|
state: State,
|
||||||
type,
|
type: string,
|
||||||
localFilter,
|
localFilter: LocalFilter,
|
||||||
stateSanitizer,
|
stateSanitizer: (state: unknown, actionId: number) => unknown,
|
||||||
actionSanitizer,
|
actionSanitizer: (action: Action<unknown>, id: number) => Action,
|
||||||
nextActionId,
|
nextActionId: number,
|
||||||
predicate
|
predicate: (currState: unknown, currAction: Action<unknown>) => boolean
|
||||||
) {
|
) {
|
||||||
if (type === 'ACTION')
|
if (type === 'ACTION')
|
||||||
return !stateSanitizer ? state : stateSanitizer(state, nextActionId - 1);
|
return !stateSanitizer ? state : stateSanitizer(state, nextActionId - 1);
|
||||||
|
@ -97,9 +136,14 @@ export function filterState(
|
||||||
localFilter ||
|
localFilter ||
|
||||||
(filter && filter !== FilterState.DO_NOT_FILTER)
|
(filter && filter !== FilterState.DO_NOT_FILTER)
|
||||||
) {
|
) {
|
||||||
const filteredStagedActionIds = [];
|
const filteredStagedActionIds: number[] = [];
|
||||||
const filteredComputedStates = [];
|
const filteredComputedStates: {
|
||||||
const sanitizedActionsById = actionSanitizer && {};
|
state: unknown;
|
||||||
|
error?: string | undefined;
|
||||||
|
}[] = [];
|
||||||
|
const sanitizedActionsById: {
|
||||||
|
[id: number]: PerformAction<Action<unknown>>;
|
||||||
|
} = actionSanitizer && {};
|
||||||
const { actionsById } = state;
|
const { actionsById } = state;
|
||||||
const { computedStates } = 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 getParams from 'get-params';
|
||||||
import jsan from 'jsan';
|
import jsan from 'jsan';
|
||||||
import { nanoid } from 'nanoid/non-secure';
|
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);
|
return id || nanoid(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
function flatTree(obj, namespace = '') {
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
let functions = [];
|
function flatTree(
|
||||||
|
obj: { [key: string]: (...args: any[]) => unknown },
|
||||||
|
namespace = ''
|
||||||
|
) {
|
||||||
|
let functions: {
|
||||||
|
name: string;
|
||||||
|
func: (...args: any[]) => unknown;
|
||||||
|
args: string[];
|
||||||
|
}[] = [];
|
||||||
Object.keys(obj).forEach((key) => {
|
Object.keys(obj).forEach((key) => {
|
||||||
const prop = obj[key];
|
const prop = obj[key];
|
||||||
if (typeof prop === 'function') {
|
if (typeof prop === 'function') {
|
||||||
|
@ -24,18 +34,23 @@ function flatTree(obj, namespace = '') {
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMethods(obj) {
|
export function getMethods(obj: unknown) {
|
||||||
if (typeof obj !== 'object') return undefined;
|
if (typeof obj !== 'object') return undefined;
|
||||||
let functions;
|
let functions:
|
||||||
let m;
|
| {
|
||||||
if (obj.__proto__) m = obj.__proto__.__proto__;
|
name: string;
|
||||||
if (!m) m = obj;
|
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) => {
|
Object.getOwnPropertyNames(m).forEach((key) => {
|
||||||
const propDescriptor = Object.getOwnPropertyDescriptor(m, key);
|
const propDescriptor = Object.getOwnPropertyDescriptor(m, key);
|
||||||
if (!propDescriptor || 'get' in propDescriptor || 'set' in propDescriptor)
|
if (!propDescriptor || 'get' in propDescriptor || 'set' in propDescriptor)
|
||||||
return;
|
return;
|
||||||
const prop = m[key];
|
const prop = m![key];
|
||||||
if (typeof prop === 'function' && key !== 'constructor') {
|
if (typeof prop === 'function' && key !== 'constructor') {
|
||||||
if (!functions) functions = [];
|
if (!functions) functions = [];
|
||||||
functions.push({
|
functions.push({
|
||||||
|
@ -47,15 +62,17 @@ export function getMethods(obj) {
|
||||||
return functions;
|
return functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getActionsArray(actionCreators) {
|
export function getActionsArray(actionCreators: {
|
||||||
|
[key: string]: (...args: any[]) => unknown;
|
||||||
|
}) {
|
||||||
if (Array.isArray(actionCreators)) return actionCreators;
|
if (Array.isArray(actionCreators)) return actionCreators;
|
||||||
return flatTree(actionCreators);
|
return flatTree(actionCreators);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable no-new-func */
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||||
const interpretArg = (arg) => new Function('return ' + arg)();
|
const interpretArg = (arg: string) => new Function('return ' + arg)();
|
||||||
|
|
||||||
function evalArgs(inArgs, restArgs) {
|
function evalArgs(inArgs: string[], restArgs: string) {
|
||||||
const args = inArgs.map(interpretArg);
|
const args = inArgs.map(interpretArg);
|
||||||
if (!restArgs) return args;
|
if (!restArgs) return args;
|
||||||
const rest = interpretArg(restArgs);
|
const rest = interpretArg(restArgs);
|
||||||
|
@ -63,8 +80,14 @@ function evalArgs(inArgs, restArgs) {
|
||||||
throw new Error('rest must be an array');
|
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') {
|
if (typeof action === 'string') {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||||
return new Function('return ' + action)();
|
return new Function('return ' + action)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,12 +96,17 @@ export function evalAction(action, actionCreators) {
|
||||||
return actionCreator(...args);
|
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') {
|
if (typeof action === 'string') {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||||
return new Function('return ' + action).call(obj);
|
return new Function('return ' + action).call(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
const args = evalArgs(action.args, action.rest);
|
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(
|
return new Function('args', `return this.${action.name}(args)`).apply(
|
||||||
obj,
|
obj,
|
||||||
args
|
args
|
||||||
|
@ -86,7 +114,7 @@ export function evalMethod(action, obj) {
|
||||||
}
|
}
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
|
|
||||||
function tryCatchStringify(obj) {
|
function tryCatchStringify(obj: unknown) {
|
||||||
try {
|
try {
|
||||||
return JSON.stringify(obj);
|
return JSON.stringify(obj);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -94,11 +122,26 @@ function tryCatchStringify(obj) {
|
||||||
if (process.env.NODE_ENV !== 'production')
|
if (process.env.NODE_ENV !== 'production')
|
||||||
console.log('Failed to stringify', err);
|
console.log('Failed to stringify', err);
|
||||||
/* eslint-enable no-console */
|
/* 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') {
|
if (typeof serialize === 'undefined') {
|
||||||
return tryCatchStringify(obj);
|
return tryCatchStringify(obj);
|
||||||
}
|
}
|
||||||
|
@ -106,23 +149,44 @@ export function stringify(obj, serialize) {
|
||||||
return jsan.stringify(
|
return jsan.stringify(
|
||||||
obj,
|
obj,
|
||||||
function (key, value) {
|
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;
|
return value;
|
||||||
},
|
},
|
||||||
null,
|
(null as unknown) as undefined,
|
||||||
true
|
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;
|
const serialize = config.serialize;
|
||||||
if (serialize) {
|
if (serialize) {
|
||||||
if (serialize === true) return { options: true };
|
if (serialize === true) return { options: true };
|
||||||
if (serialize.immutable) {
|
if (serialize.immutable) {
|
||||||
return {
|
return {
|
||||||
replacer: seralizeImmutable(serialize.immutable, serialize.refs)
|
replacer: immutableSerialize(serialize.immutable, serialize.refs)
|
||||||
.replacer,
|
.replacer,
|
||||||
options: serialize.options || true,
|
options: serialize.options || true,
|
||||||
};
|
};
|
||||||
|
@ -131,7 +195,12 @@ export function getSeralizeParameter(config, param) {
|
||||||
return { replacer: serialize.replacer, options: serialize.options || true };
|
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;
|
if (typeof value === 'undefined') return undefined;
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn(
|
console.warn(
|
||||||
|
@ -139,12 +208,15 @@ export function getSeralizeParameter(config, param) {
|
||||||
' https://github.com/zalmoxisus/redux-devtools-extension/releases/tag/v2.12.1'
|
' 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;
|
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 (!config.trace) return undefined;
|
||||||
if (typeof config.trace === 'function') return config.trace();
|
if (typeof config.trace === 'function') return config.trace();
|
||||||
|
|
||||||
|
@ -169,7 +241,7 @@ export function getStackTrace(config, toExcludeFromTrace) {
|
||||||
typeof Error.stackTraceLimit !== 'number' ||
|
typeof Error.stackTraceLimit !== 'number' ||
|
||||||
Error.stackTraceLimit > traceLimit
|
Error.stackTraceLimit > traceLimit
|
||||||
) {
|
) {
|
||||||
const frames = stack.split('\n');
|
const frames = stack!.split('\n');
|
||||||
if (frames.length > traceLimit) {
|
if (frames.length > traceLimit) {
|
||||||
stack = frames
|
stack = frames
|
||||||
.slice(0, traceLimit + extraFrames + (frames[0] === 'Error' ? 1 : 0))
|
.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 { Provider } from 'react-redux';
|
||||||
import { createStore, applyMiddleware } from 'redux';
|
import { createStore, applyMiddleware } from 'redux';
|
||||||
import { mount } from 'enzyme';
|
import { mount, ReactWrapper } from 'enzyme';
|
||||||
// import { mountToJson } from 'enzyme-to-json';
|
// import { mountToJson } from 'enzyme-to-json';
|
||||||
import App from '../src/app/containers/App';
|
import App from '../src/app/containers/App';
|
||||||
import api from '../src/app/middlewares/api';
|
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 { DATA_TYPE_KEY } from '../src/app/constants/dataTypes';
|
||||||
import stringifyJSON from '../src/app/utils/stringifyJSON';
|
import stringifyJSON from '../src/app/utils/stringifyJSON';
|
||||||
|
|
||||||
let wrapper;
|
let wrapper: ReactWrapper<unknown, unknown, Component>;
|
||||||
|
|
||||||
const store = createStore(rootReducer, applyMiddleware(exportState, api));
|
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');
|
import * as path from 'path';
|
||||||
const webpack = require('webpack');
|
import * as webpack from 'webpack';
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
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',
|
mode: env.development ? 'development' : 'production',
|
||||||
entry: {
|
entry: {
|
||||||
app: './index.js',
|
app: './src/index',
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'build/' + env.platform),
|
path: path.resolve(__dirname, `build/${env.platform as string}`),
|
||||||
publicPath: '',
|
publicPath: '',
|
||||||
filename: 'js/[name].js',
|
filename: 'js/[name].js',
|
||||||
sourceMapFilename: 'js/[name].map',
|
sourceMapFilename: 'js/[name].map',
|
||||||
|
@ -16,7 +17,7 @@ module.exports = (env = {}) => ({
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.(js|ts)x?$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
|
@ -44,6 +45,9 @@ module.exports = (env = {}) => ({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': {
|
'process.env': {
|
||||||
|
@ -56,6 +60,11 @@ module.exports = (env = {}) => ({
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: 'assets/index.html',
|
template: 'assets/index.html',
|
||||||
}),
|
}),
|
||||||
|
new ForkTsCheckerWebpackPlugin({
|
||||||
|
typescript: {
|
||||||
|
configFile: 'tsconfig.json',
|
||||||
|
},
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: false,
|
minimize: false,
|
|
@ -1,10 +1,11 @@
|
||||||
const path = require('path');
|
import * as path from 'path';
|
||||||
const webpack = require('webpack');
|
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',
|
mode: env.production ? 'production' : 'development',
|
||||||
entry: {
|
entry: {
|
||||||
app: ['./src/app/index.js'],
|
app: ['./src/app/index'],
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
library: 'ReduxDevTools',
|
library: 'ReduxDevTools',
|
||||||
|
@ -18,7 +19,7 @@ module.exports = (env = {}) => ({
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.(js|ts)x?$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
|
@ -41,6 +42,9 @@ module.exports = (env = {}) => ({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': {
|
'process.env': {
|
||||||
|
@ -48,6 +52,11 @@ module.exports = (env = {}) => ({
|
||||||
PLATFORM: JSON.stringify('web'),
|
PLATFORM: JSON.stringify('web'),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
new ForkTsCheckerWebpackPlugin({
|
||||||
|
typescript: {
|
||||||
|
configFile: 'tsconfig.json',
|
||||||
|
},
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
externals: {
|
externals: {
|
||||||
react: {
|
react: {
|
|
@ -25,7 +25,7 @@ export interface TabComponentProps<S, A extends Action<unknown>> {
|
||||||
base16Theme: Base16Theme;
|
base16Theme: Base16Theme;
|
||||||
invertTheme: boolean;
|
invertTheme: boolean;
|
||||||
isWideLayout: boolean;
|
isWideLayout: boolean;
|
||||||
dataTypeKey: string | undefined;
|
dataTypeKey: string | symbol | undefined;
|
||||||
delta: Delta | null | undefined | false;
|
delta: Delta | null | undefined | false;
|
||||||
action: A;
|
action: A;
|
||||||
nextState: S;
|
nextState: S;
|
||||||
|
@ -67,7 +67,7 @@ interface Props<S, A extends Action<unknown>> {
|
||||||
actions: { [actionId: number]: PerformAction<A> };
|
actions: { [actionId: number]: PerformAction<A> };
|
||||||
selectedActionId: number | null;
|
selectedActionId: number | null;
|
||||||
startActionId: number | null;
|
startActionId: number | null;
|
||||||
dataTypeKey: string | undefined;
|
dataTypeKey: string | symbol | undefined;
|
||||||
monitorState: DevtoolsInspectorState;
|
monitorState: DevtoolsInspectorState;
|
||||||
updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;
|
updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;
|
||||||
styling: StylingFunction;
|
styling: StylingFunction;
|
||||||
|
|
|
@ -128,7 +128,7 @@ function createThemeState<S, A extends Action<unknown>>(
|
||||||
return { base16Theme, styling };
|
return { base16Theme, styling };
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExternalProps<S, A extends Action<unknown>> {
|
export interface ExternalProps<S, A extends Action<unknown>> {
|
||||||
dispatch: Dispatch<
|
dispatch: Dispatch<
|
||||||
DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState>
|
DevtoolsInspectorAction | LiftedAction<S, A, DevtoolsInspectorState>
|
||||||
>;
|
>;
|
||||||
|
@ -142,7 +142,7 @@ interface ExternalProps<S, A extends Action<unknown>> {
|
||||||
hideMainButtons?: boolean;
|
hideMainButtons?: boolean;
|
||||||
hideActionButtons?: boolean;
|
hideActionButtons?: boolean;
|
||||||
invertTheme: boolean;
|
invertTheme: boolean;
|
||||||
dataTypeKey?: string;
|
dataTypeKey?: string | symbol;
|
||||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
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;
|
hideMainButtons?: boolean;
|
||||||
hideActionButtons?: boolean;
|
hideActionButtons?: boolean;
|
||||||
invertTheme: boolean;
|
invertTheme: boolean;
|
||||||
dataTypeKey?: string;
|
dataTypeKey?: string | symbol;
|
||||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { DevtoolsInspectorProps } from './DevtoolsInspector';
|
||||||
const UPDATE_MONITOR_STATE =
|
const UPDATE_MONITOR_STATE =
|
||||||
'@@redux-devtools-inspector-monitor/UPDATE_MONITOR_STATE';
|
'@@redux-devtools-inspector-monitor/UPDATE_MONITOR_STATE';
|
||||||
|
|
||||||
interface UpdateMonitorStateAction {
|
export interface UpdateMonitorStateAction {
|
||||||
type: typeof UPDATE_MONITOR_STATE;
|
type: typeof UPDATE_MONITOR_STATE;
|
||||||
monitorState: Partial<DevtoolsInspectorState>;
|
monitorState: Partial<DevtoolsInspectorState>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ interface Props {
|
||||||
expandable: boolean
|
expandable: boolean
|
||||||
) => React.ReactNode;
|
) => React.ReactNode;
|
||||||
isWideLayout: boolean;
|
isWideLayout: boolean;
|
||||||
dataTypeKey: string | undefined;
|
dataTypeKey: string | symbol | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
|
|
|
@ -73,7 +73,7 @@ const getItemString = (
|
||||||
styling: StylingFunction,
|
styling: StylingFunction,
|
||||||
type: string,
|
type: string,
|
||||||
data: any,
|
data: any,
|
||||||
dataTypeKey: string | undefined,
|
dataTypeKey: string | symbol | undefined,
|
||||||
isWideLayout: boolean,
|
isWideLayout: boolean,
|
||||||
isDiff?: boolean
|
isDiff?: boolean
|
||||||
) => (
|
) => (
|
||||||
|
|
|
@ -35,3 +35,4 @@ export default function (
|
||||||
serialize: serialize,
|
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