This commit is contained in:
Nathan Bierema 2020-10-18 17:11:48 -04:00
parent 1895d22370
commit bb87b3e2f2
8 changed files with 115 additions and 38 deletions

View File

@ -37,8 +37,12 @@ import {
} from '../constants/socketActionTypes'; } from '../constants/socketActionTypes';
import { Action } from 'redux'; import { Action } from 'redux';
let monitorReducer; let monitorReducer: (
let monitorProps = {}; monitorProps: unknown,
state: unknown | undefined,
action: Action<unknown>
) => unknown;
let monitorProps: unknown = {};
interface ChangeSectionAction { interface ChangeSectionAction {
readonly type: typeof CHANGE_SECTION; readonly type: typeof CHANGE_SECTION;
@ -66,9 +70,25 @@ export function changeTheme(data: ChangeThemeData): ChangeThemeAction {
return { type: CHANGE_THEME, ...data.formData }; return { type: CHANGE_THEME, ...data.formData };
} }
interface MonitorActionAction { 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; type: typeof MONITOR_ACTION;
action: Action<unknown>; action: InitMonitorAction;
monitorReducer: (
monitorProps: unknown,
state: unknown | undefined,
action: Action<unknown>
) => unknown;
monitorProps: unknown;
} }
interface LiftedActionAction { interface LiftedActionAction {
type: typeof LIFTED_ACTION; type: typeof LIFTED_ACTION;
@ -76,7 +96,7 @@ interface LiftedActionAction {
action: Action<unknown>; action: Action<unknown>;
} }
export function liftedDispatch( export function liftedDispatch(
action: Action<unknown> action: InitMonitorAction
): MonitorActionAction | LiftedActionAction { ): MonitorActionAction | LiftedActionAction {
if (action.type[0] === '@') { if (action.type[0] === '@') {
if (action.type === '@@INIT_MONITOR') { if (action.type === '@@INIT_MONITOR') {
@ -188,7 +208,7 @@ export function toggleDispatcher(): ToggleDispatcherAction {
} }
export type ConnectionType = 'disabled' | 'remotedev' | 'custom'; export type ConnectionType = 'disabled' | 'remotedev' | 'custom';
interface ConnectionOptions { export interface ConnectionOptions {
readonly type: ConnectionType; readonly type: ConnectionType;
readonly hostname: string; readonly hostname: string;
readonly port: number; readonly port: number;

View File

@ -1,22 +1,41 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withTheme } from 'styled-components'; import { withTheme } from 'styled-components';
import { LiftedAction } from 'redux-devtools-instrument'; import { LiftedAction, LiftedState } from 'redux-devtools-instrument';
import { Action } from 'redux'; import { Action } from 'redux';
import { Monitor } from 'redux-devtools';
import getMonitor from '../utils/getMonitor'; import getMonitor from '../utils/getMonitor';
import { InitMonitorAction } from '../actions';
class DevTools extends Component { interface Props {
constructor(props) { monitor: string;
dispatch: (
action: LiftedAction<unknown, Action<unknown>, unknown> | InitMonitorAction
) => void;
}
class DevTools extends Component<Props> {
monitorProps: unknown;
Monitor?: Monitor<
unknown,
Action<unknown>,
LiftedState<unknown, Action<unknown>, unknown>,
unknown,
Action<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; const update = this.Monitor!.update;
if (update) { if (update) {
let newMonitorState; let newMonitorState;
const monitorState = props.monitorState; const monitorState = props.monitorState;
@ -54,7 +73,9 @@ class DevTools extends Component {
); );
} }
dispatch = (action: LiftedAction<unknown, Action<unknown>, unknown>) => { dispatch = (
action: LiftedAction<unknown, Action<unknown>, unknown> | InitMonitorAction
) => {
this.props.dispatch(action); this.props.dispatch(action);
}; };

View File

@ -4,8 +4,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; 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';
export const DispatcherContainer = styled.div` export const DispatcherContainer = styled.div`
@ -47,7 +46,10 @@ export const ActionContainer = styled.div`
} }
`; `;
class Dispatcher extends Component { type DispatchProps = ResolveThunks<typeof actionCreators>;
type Props = DispatchProps;
class Dispatcher extends Component<Props> {
static propTypes = { static propTypes = {
options: PropTypes.object.isRequired, options: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
@ -208,10 +210,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);

View File

@ -2,6 +2,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; 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, LiftedState } from 'redux-devtools-instrument';
import { Action, Dispatch } from 'redux';
const SliderWrapper = styled.div` const SliderWrapper = styled.div`
border-color: ${(props) => props.theme.base02}; border-color: ${(props) => props.theme.base02};
@ -9,8 +11,14 @@ const SliderWrapper = styled.div`
border-width: 1px 0; border-width: 1px 0;
`; `;
class Slider extends Component { interface Props {
shouldComponentUpdate(nextProps) { liftedState: LiftedState<unknown, Action<unknown>, unknown>;
dispatch: Dispatch<LiftedAction<unknown, Action<unknown>, unknown>>;
theme:
}
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

View File

@ -2,17 +2,26 @@ import 'devui/lib/presets';
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; 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,
}); });
this.forceUpdate(); this.forceUpdate();
}); });

View File

@ -1,6 +1,6 @@
import socketCluster, { SCClientSocket } from 'socketcluster-client'; import socketCluster, { SCClientSocket } from 'socketcluster-client';
import { stringify } from 'jsan'; import { stringify } from 'jsan';
import { Dispatch, Middleware, MiddlewareAPI, Store } from 'redux'; 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';

View File

@ -5,9 +5,14 @@ import {
TOGGLE_SLIDER, TOGGLE_SLIDER,
TOGGLE_DISPATCHER, TOGGLE_DISPATCHER,
} from '../constants/actionTypes'; } from '../constants/actionTypes';
import { StoreAction } from '../actions'; import { MonitorActionAction, StoreAction } from '../actions';
export interface MonitorState {} export interface MonitorState {
selected: string;
monitorState: unknown | undefined;
sliderIsOpen: boolean;
dispatcherIsOpen: boolean;
}
const initialState = { const initialState = {
selected: 'InspectorMonitor', selected: 'InspectorMonitor',
@ -16,7 +21,10 @@ const initialState = {
dispatcherIsOpen: false, dispatcherIsOpen: false,
}; };
export function dispatchMonitorAction(state, action) { export function dispatchMonitorAction(
state: MonitorState,
action: MonitorActionAction
) {
return { return {
...state, ...state,
monitorState: monitorState:

View File

@ -1,20 +1,31 @@
import { createStore, compose, applyMiddleware } from 'redux'; import { createStore, compose, applyMiddleware, Store } from 'redux';
import localForage from 'localforage'; import localForage from 'localforage';
import { getStoredState, createPersistor } from 'redux-persist'; import {
getStoredState,
createPersistor,
PersistorConfig,
} from 'redux-persist';
import api from '../middlewares/api'; import api from '../middlewares/api';
import exportState from '../middlewares/exportState'; import exportState from '../middlewares/exportState';
import rootReducer from '../reducers'; import rootReducer, { StoreState } from '../reducers';
import { StoreAction } from '../actions';
export default function configureStore(callback, key) { export default function configureStore(
const persistConfig = { callback: (
store: Store<StoreState, StoreAction>,
restoredState: Partial<StoreState> | undefined
) => void,
key?: string
) {
const persistConfig: PersistorConfig = ({
keyPrefix: `redux-devtools${key || ''}:`, keyPrefix: `redux-devtools${key || ''}:`,
blacklist: ['instances', 'socket'], blacklist: ['instances', 'socket'],
storage: localForage, storage: localForage,
serialize: (data) => data, serialize: (data: unknown) => data,
deserialize: (data) => data, deserialize: (data: unknown) => data,
}; } as unknown) as PersistorConfig;
getStoredState(persistConfig, (err, restoredState) => { getStoredState<StoreState>(persistConfig, (err, restoredState) => {
let composeEnhancers = compose; let composeEnhancers = compose;
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) { if (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {