mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-22 22:19:48 +03:00
stash
This commit is contained in:
parent
35fc6ec837
commit
b2de052522
|
@ -142,7 +142,7 @@ const mergeStylings = (
|
|||
|
||||
const getStylingByKeys = (
|
||||
mergedStyling: StylingConfig,
|
||||
keys: (string | false) | (string | false)[],
|
||||
keys: (string | false | undefined) | (string | false | undefined)[],
|
||||
...args: any[]
|
||||
): Styling => {
|
||||
if (keys === null) {
|
||||
|
|
|
@ -27,6 +27,6 @@ export type StylingConfig = {
|
|||
export type Theme = string | Base16Theme | StylingConfig;
|
||||
|
||||
export type StylingFunction = (
|
||||
keys: (string | false) | (string | false)[],
|
||||
keys: (string | false | undefined) | (string | false | undefined)[],
|
||||
...rest: any[]
|
||||
) => Styling;
|
||||
|
|
|
@ -5,7 +5,6 @@ const isProduction = process.env.NODE_ENV === 'production';
|
|||
|
||||
module.exports = {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
devtool: 'eval',
|
||||
entry: isProduction
|
||||
? ['./demo/src/index']
|
||||
: [
|
||||
|
@ -18,10 +17,6 @@ module.exports = {
|
|||
filename: 'bundle.js',
|
||||
publicPath: isProduction ? 'static/' : '/static/',
|
||||
},
|
||||
plugins: isProduction ? [] : [new webpack.HotModuleReplacementPlugin()],
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
@ -34,6 +29,10 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
plugins: isProduction ? [] : [new webpack.HotModuleReplacementPlugin()],
|
||||
devServer: isProduction
|
||||
? null
|
||||
: {
|
||||
|
@ -46,4 +45,5 @@ module.exports = {
|
|||
},
|
||||
historyApiFallback: true,
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
};
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/dateformat": "^3.0.1",
|
||||
"@types/hex-rgba": "^1.0.0",
|
||||
"@types/lodash.debounce": "^4.0.6",
|
||||
"@types/react": "^16.9.46",
|
||||
"@types/react-dragula": "^1.1.0",
|
||||
|
|
|
@ -164,18 +164,20 @@ export default class ActionList<
|
|||
isSelected={
|
||||
(startActionId !== null &&
|
||||
actionId >= startActionId &&
|
||||
actionId <= selectedActionId) ||
|
||||
actionId <= (selectedActionId as number)) ||
|
||||
actionId === selectedActionId
|
||||
}
|
||||
isInFuture={
|
||||
actionIds.indexOf(actionId) > actionIds.indexOf(currentActionId)
|
||||
}
|
||||
onSelect={(e) => onSelect(e, actionId)}
|
||||
onSelect={(e: React.MouseEvent<HTMLDivElement>) =>
|
||||
onSelect(e, actionId)
|
||||
}
|
||||
timestamps={getTimestamps(actions, actionIds, actionId)}
|
||||
action={actions[actionId].action}
|
||||
onToggleClick={() => onToggleAction(actionId)}
|
||||
onJumpClick={() => onJumpToState(actionId)}
|
||||
onCommitClick={() => onCommit(actionId)}
|
||||
onCommitClick={() => onCommit()}
|
||||
hideActionButtons={hideActionButtons}
|
||||
isSkipped={skippedActionIds.indexOf(actionId) !== -1}
|
||||
/>
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
import RightSlider from './RightSlider';
|
||||
|
||||
const getActiveButtons = (hasSkippedActions) =>
|
||||
[hasSkippedActions && 'Sweep', 'Commit'].filter((a) => a);
|
||||
const getActiveButtons = (hasSkippedActions: boolean): ('Sweep' | 'Commit')[] =>
|
||||
[hasSkippedActions && 'Sweep', 'Commit'].filter(
|
||||
(a): a is 'Sweep' | 'Commit' => !!a
|
||||
);
|
||||
|
||||
const ActionListHeader = ({
|
||||
interface Props {
|
||||
styling: StylingFunction;
|
||||
onSearch: (value: string) => void;
|
||||
onCommit: () => void;
|
||||
onSweep: () => void;
|
||||
hideMainButtons: boolean | undefined;
|
||||
hasSkippedActions: boolean;
|
||||
hasStagedActions: boolean;
|
||||
}
|
||||
|
||||
const ActionListHeader: FunctionComponent<Props> = ({
|
||||
styling,
|
||||
onSearch,
|
||||
hasSkippedActions,
|
||||
|
@ -48,4 +62,14 @@ const ActionListHeader = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
ActionListHeader.propTypes = {
|
||||
styling: PropTypes.func.isRequired,
|
||||
onSearch: PropTypes.func.isRequired,
|
||||
onCommit: PropTypes.func.isRequired,
|
||||
onSweep: PropTypes.func.isRequired,
|
||||
hideMainButtons: PropTypes.bool,
|
||||
hasSkippedActions: PropTypes.bool.isRequired,
|
||||
hasStagedActions: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default ActionListHeader;
|
||||
|
|
|
@ -1,10 +1,43 @@
|
|||
import React, { Component } from 'react';
|
||||
import { DEFAULT_STATE } from './redux';
|
||||
import { Base16Theme } from 'redux-devtools-themes';
|
||||
import { Action } from 'redux';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
import { PerformAction } from 'redux-devtools';
|
||||
import { Delta } from 'jsondiffpatch';
|
||||
import { DEFAULT_STATE, DevtoolsInspectorState } from './redux';
|
||||
import ActionPreviewHeader from './ActionPreviewHeader';
|
||||
import DiffTab from './tabs/DiffTab';
|
||||
import StateTab from './tabs/StateTab';
|
||||
import ActionTab from './tabs/ActionTab';
|
||||
|
||||
export interface TabComponentProps<S, A extends Action<unknown>> {
|
||||
labelRenderer: (
|
||||
keyPath: (string | number)[],
|
||||
nodeType: string,
|
||||
expanded: boolean,
|
||||
expandable: boolean
|
||||
) => React.ReactNode;
|
||||
styling: StylingFunction;
|
||||
computedStates: { state: S; error?: string }[];
|
||||
actions: { [actionId: number]: PerformAction<A> };
|
||||
selectedActionId: number | null;
|
||||
startActionId: number | null;
|
||||
base16Theme: Base16Theme;
|
||||
invertTheme: boolean;
|
||||
isWideLayout: boolean;
|
||||
dataTypeKey: string | undefined;
|
||||
delta: Delta | null | undefined | false;
|
||||
action: A;
|
||||
nextState: S;
|
||||
monitorState: DevtoolsInspectorState;
|
||||
updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;
|
||||
}
|
||||
|
||||
export interface Tab<S, A extends Action<unknown>> {
|
||||
name: string;
|
||||
component: React.ComponentType<TabComponentProps<S, A>>;
|
||||
}
|
||||
|
||||
const DEFAULT_TABS = [
|
||||
{
|
||||
name: 'Action',
|
||||
|
@ -20,7 +53,32 @@ const DEFAULT_TABS = [
|
|||
},
|
||||
];
|
||||
|
||||
class ActionPreview extends Component {
|
||||
interface Props<S, A extends Action<unknown>> {
|
||||
base16Theme: Base16Theme;
|
||||
invertTheme: boolean;
|
||||
isWideLayout: boolean;
|
||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||
tabName: string;
|
||||
delta: Delta | null | undefined | false;
|
||||
error: string | undefined;
|
||||
nextState: S;
|
||||
computedStates: { state: S; error?: string }[];
|
||||
action: A;
|
||||
actions: { [actionId: number]: PerformAction<A> };
|
||||
selectedActionId: number | null;
|
||||
startActionId: number | null;
|
||||
dataTypeKey: string | undefined;
|
||||
monitorState: DevtoolsInspectorState;
|
||||
updateMonitorState: (monitorState: Partial<DevtoolsInspectorState>) => void;
|
||||
styling: StylingFunction;
|
||||
onInspectPath: (path: (string | number)[]) => void;
|
||||
inspectedPath: (string | number)[];
|
||||
onSelectTab: (tabName: string) => void;
|
||||
}
|
||||
|
||||
class ActionPreview<S, A extends Action<unknown>> extends Component<
|
||||
Props<S, A>
|
||||
> {
|
||||
static defaultProps = {
|
||||
tabName: DEFAULT_STATE.tabName,
|
||||
};
|
||||
|
@ -49,21 +107,21 @@ class ActionPreview extends Component {
|
|||
updateMonitorState,
|
||||
} = this.props;
|
||||
|
||||
const renderedTabs =
|
||||
const renderedTabs: Tab<S, A>[] =
|
||||
typeof tabs === 'function'
|
||||
? tabs(DEFAULT_TABS)
|
||||
? tabs(DEFAULT_TABS as Tab<S, A>[])
|
||||
: tabs
|
||||
? tabs
|
||||
: DEFAULT_TABS;
|
||||
: (DEFAULT_TABS as Tab<S, A>[]);
|
||||
|
||||
const { component: TabComponent } =
|
||||
renderedTabs.find((tab) => tab.name === tabName) ||
|
||||
renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName);
|
||||
renderedTabs.find((tab) => tab.name === DEFAULT_STATE.tabName)!;
|
||||
|
||||
return (
|
||||
<div key="actionPreview" {...styling('actionPreview')}>
|
||||
<ActionPreviewHeader
|
||||
tabs={renderedTabs}
|
||||
tabs={(renderedTabs as unknown) as Tab<unknown, Action<unknown>>[]}
|
||||
{...{ styling, inspectedPath, onInspectPath, tabName, onSelectTab }}
|
||||
/>
|
||||
{!error && (
|
||||
|
@ -94,7 +152,11 @@ class ActionPreview extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
labelRenderer = ([key, ...rest], nodeType, expanded) => {
|
||||
labelRenderer = (
|
||||
[key, ...rest]: (string | number)[],
|
||||
nodeType: string,
|
||||
expanded: boolean
|
||||
) => {
|
||||
const { styling, onInspectPath, inspectedPath } = this.props;
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Action } from 'redux';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
import { Tab } from './ActionPreview';
|
||||
|
||||
const ActionPreviewHeader = ({
|
||||
interface Props<S, A extends Action<unknown>> {
|
||||
tabs: Tab<S, A>[];
|
||||
styling: StylingFunction;
|
||||
inspectedPath: (string | number)[];
|
||||
onInspectPath: (path: (string | number)[]) => void;
|
||||
tabName: string;
|
||||
onSelectTab: (tabName: string) => void;
|
||||
}
|
||||
|
||||
const ActionPreviewHeader: FunctionComponent<Props<
|
||||
unknown,
|
||||
Action<unknown>
|
||||
>> = ({
|
||||
styling,
|
||||
inspectedPath,
|
||||
onInspectPath,
|
||||
|
@ -57,4 +73,13 @@ const ActionPreviewHeader = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
ActionPreviewHeader.propTypes = {
|
||||
tabs: PropTypes.array.isRequired,
|
||||
styling: PropTypes.func.isRequired,
|
||||
inspectedPath: PropTypes.array.isRequired,
|
||||
onInspectPath: PropTypes.func.isRequired,
|
||||
tabName: PropTypes.string.isRequired,
|
||||
onSelectTab: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ActionPreviewHeader;
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
base16Themes,
|
||||
} from './utils/createStylingFromTheme';
|
||||
import ActionList from './ActionList';
|
||||
import ActionPreview from './ActionPreview';
|
||||
import ActionPreview, { Tab } from './ActionPreview';
|
||||
import getInspectedState from './utils/getInspectedState';
|
||||
import createDiffPatcher from './createDiffPatcher';
|
||||
import {
|
||||
|
@ -144,7 +144,7 @@ export interface DevtoolsInspectorProps<S, A extends Action<unknown>>
|
|||
hideActionButtons?: boolean;
|
||||
invertTheme: boolean;
|
||||
dataTypeKey?: string;
|
||||
tabs: unknown;
|
||||
tabs: Tab<S, A>[] | ((tabs: Tab<S, A>[]) => Tab<S, A>[]);
|
||||
}
|
||||
|
||||
interface State<S, A extends Action<unknown>> {
|
||||
|
@ -342,7 +342,9 @@ export default class DevtoolsInspector<
|
|||
monitorState={this.props.monitorState}
|
||||
updateMonitorState={this.updateMonitorState}
|
||||
styling={styling}
|
||||
onInspectPath={this.handleInspectPath.bind(this, inspectedPathType)}
|
||||
onInspectPath={(path: (string | number)[]) =>
|
||||
this.handleInspectPath(inspectedPathType, path)
|
||||
}
|
||||
inspectedPath={monitorState[inspectedPathType]}
|
||||
onSelectTab={this.handleSelectTab}
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
|
||||
const RightSlider = ({ styling, shown, children, rotate }) => (
|
||||
interface Props {
|
||||
styling: StylingFunction;
|
||||
shown?: boolean;
|
||||
children: React.ReactNode;
|
||||
rotate?: boolean;
|
||||
}
|
||||
|
||||
const RightSlider: FunctionComponent<Props> = ({
|
||||
styling,
|
||||
shown,
|
||||
children,
|
||||
rotate,
|
||||
}) => (
|
||||
<div
|
||||
{...styling([
|
||||
'rightSlider',
|
||||
|
@ -15,7 +28,10 @@ const RightSlider = ({ styling, shown, children, rotate }) => (
|
|||
);
|
||||
|
||||
RightSlider.propTypes = {
|
||||
styling: PropTypes.func.isRequired,
|
||||
shown: PropTypes.bool,
|
||||
children: PropTypes.any.isRequired,
|
||||
rotate: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default RightSlider;
|
||||
|
|
|
@ -1,28 +1,37 @@
|
|||
import { DiffPatcher } from 'jsondiffpatch';
|
||||
import { DiffContext, DiffPatcher } from 'jsondiffpatch';
|
||||
|
||||
const defaultObjectHash = (o, idx) =>
|
||||
const defaultObjectHash = (o: any, idx: number) =>
|
||||
(o === null && '$$null') ||
|
||||
(o && (o.id || o.id === 0) && `$$id:${JSON.stringify(o.id)}`) ||
|
||||
(o && (o._id || o._id === 0) && `$$_id:${JSON.stringify(o._id)}`) ||
|
||||
'$$index:' + idx;
|
||||
`$$index:${idx}`;
|
||||
|
||||
const defaultPropertyFilter = (name, context) =>
|
||||
const defaultPropertyFilter = (name: string, context: DiffContext) =>
|
||||
typeof context.left[name] !== 'function' &&
|
||||
typeof context.right[name] !== 'function';
|
||||
|
||||
const defaultDiffPatcher = new DiffPatcher({
|
||||
arrays: { detectMove: false },
|
||||
arrays: { detectMove: false } as {
|
||||
detectMove: boolean;
|
||||
includeValueOnMove: boolean;
|
||||
},
|
||||
objectHash: defaultObjectHash,
|
||||
propertyFilter: defaultPropertyFilter,
|
||||
});
|
||||
|
||||
export default function createDiffPatcher(objectHash, propertyFilter) {
|
||||
export default function createDiffPatcher(
|
||||
objectHash: ((item: unknown, index: number) => string) | undefined,
|
||||
propertyFilter: ((name: string, context: DiffContext) => boolean) | undefined
|
||||
) {
|
||||
if (!objectHash && !propertyFilter) {
|
||||
return defaultDiffPatcher;
|
||||
}
|
||||
|
||||
return new DiffPatcher({
|
||||
arrays: { detectMove: false },
|
||||
arrays: { detectMove: false } as {
|
||||
detectMove: boolean;
|
||||
includeValueOnMove: boolean;
|
||||
},
|
||||
objectHash: objectHash || defaultObjectHash,
|
||||
propertyFilter: propertyFilter || defaultPropertyFilter,
|
||||
});
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import JSONTree from 'react-json-tree';
|
||||
import { Action } from 'redux';
|
||||
import getItemString from './getItemString';
|
||||
import getJsonTreeTheme from './getJsonTreeTheme';
|
||||
import { TabComponentProps } from '../ActionPreview';
|
||||
|
||||
const ActionTab = ({
|
||||
const ActionTab: FunctionComponent<TabComponentProps<
|
||||
unknown,
|
||||
Action<unknown>
|
||||
>> = ({
|
||||
action,
|
||||
styling,
|
||||
base16Theme,
|
||||
|
@ -24,4 +30,14 @@ const ActionTab = ({
|
|||
/>
|
||||
);
|
||||
|
||||
ActionTab.propTypes = {
|
||||
action: PropTypes.any.isRequired,
|
||||
styling: PropTypes.func.isRequired,
|
||||
base16Theme: PropTypes.any.isRequired,
|
||||
invertTheme: PropTypes.bool.isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
dataTypeKey: PropTypes.string,
|
||||
isWideLayout: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default ActionTab;
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import React from 'react';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import JSONDiff from './JSONDiff';
|
||||
import { TabComponentProps } from '../ActionPreview';
|
||||
import { Action } from 'redux';
|
||||
|
||||
const DiffTab = ({
|
||||
const DiffTab: FunctionComponent<TabComponentProps<
|
||||
unknown,
|
||||
Action<unknown>
|
||||
>> = ({
|
||||
delta,
|
||||
styling,
|
||||
base16Theme,
|
||||
invertTheme,
|
||||
labelRenderer,
|
||||
isWideLayout,
|
||||
dataTypeKey,
|
||||
}) => (
|
||||
<JSONDiff
|
||||
{...{
|
||||
|
@ -17,8 +24,19 @@ const DiffTab = ({
|
|||
invertTheme,
|
||||
labelRenderer,
|
||||
isWideLayout,
|
||||
dataTypeKey,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
DiffTab.propTypes = {
|
||||
delta: PropTypes.any,
|
||||
styling: PropTypes.func.isRequired,
|
||||
base16Theme: PropTypes.any.isRequired,
|
||||
invertTheme: PropTypes.bool.isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
isWideLayout: PropTypes.bool.isRequired,
|
||||
dataTypeKey: PropTypes.string,
|
||||
};
|
||||
|
||||
export default DiffTab;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
import React, { Component } from 'react';
|
||||
import JSONTree from 'react-json-tree';
|
||||
import { stringify } from 'javascript-stringify';
|
||||
import { Delta } from 'jsondiffpatch';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
import { Base16Theme } from 'redux-devtools-themes';
|
||||
import getItemString from './getItemString';
|
||||
import getJsonTreeTheme from './getJsonTreeTheme';
|
||||
|
||||
function stringifyAndShrink(val, isWideLayout) {
|
||||
function stringifyAndShrink(val: any, isWideLayout?: boolean) {
|
||||
if (val === null) {
|
||||
return 'null';
|
||||
}
|
||||
|
@ -19,12 +22,16 @@ function stringifyAndShrink(val, isWideLayout) {
|
|||
return str.length > 22 ? `${str.substr(0, 15)}…${str.substr(-5)}` : str;
|
||||
}
|
||||
|
||||
const expandFirstLevel = (keyName, data, level) => level <= 1;
|
||||
const expandFirstLevel = (
|
||||
keyName: (string | number)[],
|
||||
data: any,
|
||||
level: number
|
||||
) => level <= 1;
|
||||
|
||||
function prepareDelta(value) {
|
||||
function prepareDelta(value: any) {
|
||||
if (value && value._t === 'a') {
|
||||
const res = {};
|
||||
for (let key in value) {
|
||||
const res: { [key: string]: any } = {};
|
||||
for (const key in value) {
|
||||
if (key !== '_t') {
|
||||
if (key[0] === '_' && !value[key.substr(1)]) {
|
||||
res[key.substr(1)] = value[key];
|
||||
|
@ -41,14 +48,33 @@ function prepareDelta(value) {
|
|||
return value;
|
||||
}
|
||||
|
||||
export default class JSONDiff extends Component {
|
||||
state = { data: {} };
|
||||
interface Props {
|
||||
delta: Delta | null | undefined | false;
|
||||
styling: StylingFunction;
|
||||
base16Theme: Base16Theme;
|
||||
invertTheme: boolean;
|
||||
labelRenderer: (
|
||||
keyPath: (string | number)[],
|
||||
nodeType: string,
|
||||
expanded: boolean,
|
||||
expandable: boolean
|
||||
) => React.ReactNode;
|
||||
isWideLayout: boolean;
|
||||
dataTypeKey: string | undefined;
|
||||
}
|
||||
|
||||
interface State {
|
||||
data: any;
|
||||
}
|
||||
|
||||
export default class JSONDiff extends Component<Props, State> {
|
||||
state: State = { data: {} };
|
||||
|
||||
componentDidMount() {
|
||||
this.updateData();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.delta !== this.props.delta) {
|
||||
this.updateData();
|
||||
}
|
||||
|
@ -84,7 +110,7 @@ export default class JSONDiff extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
getItemString = (type, data) =>
|
||||
getItemString = (type: string, data: any) =>
|
||||
getItemString(
|
||||
this.props.styling,
|
||||
type,
|
||||
|
@ -94,10 +120,10 @@ export default class JSONDiff extends Component {
|
|||
true
|
||||
);
|
||||
|
||||
valueRenderer = (raw, value) => {
|
||||
valueRenderer = (raw: any, value: any) => {
|
||||
const { styling, isWideLayout } = this.props;
|
||||
|
||||
function renderSpan(name, body) {
|
||||
function renderSpan(name: string, body: string) {
|
||||
return (
|
||||
<span key={name} {...styling(['diff', name])}>
|
||||
{body}
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import JSONTree from 'react-json-tree';
|
||||
import { Action } from 'redux';
|
||||
import getItemString from './getItemString';
|
||||
import getJsonTreeTheme from './getJsonTreeTheme';
|
||||
import { TabComponentProps } from '../ActionPreview';
|
||||
|
||||
const StateTab = ({
|
||||
const StateTab: React.FunctionComponent<TabComponentProps<
|
||||
any,
|
||||
Action<unknown>
|
||||
>> = ({
|
||||
nextState,
|
||||
styling,
|
||||
base16Theme,
|
||||
|
@ -24,4 +30,14 @@ const StateTab = ({
|
|||
/>
|
||||
);
|
||||
|
||||
StateTab.propTypes = {
|
||||
nextState: PropTypes.any.isRequired,
|
||||
styling: PropTypes.func.isRequired,
|
||||
base16Theme: PropTypes.any.isRequired,
|
||||
invertTheme: PropTypes.bool.isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
dataTypeKey: PropTypes.string,
|
||||
isWideLayout: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
export default StateTab;
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
import React from 'react';
|
||||
import { Iterable } from 'immutable';
|
||||
import { isCollection, isIndexed, isKeyed } from 'immutable';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
import isIterable from '../utils/isIterable';
|
||||
|
||||
const IS_IMMUTABLE_KEY = '@@__IS_IMMUTABLE__@@';
|
||||
|
||||
function isImmutable(value) {
|
||||
return (
|
||||
Iterable.isKeyed(value) ||
|
||||
Iterable.isIndexed(value) ||
|
||||
Iterable.isIterable(value)
|
||||
);
|
||||
function isImmutable(value: any) {
|
||||
return isKeyed(value) || isIndexed(value) || isCollection(value);
|
||||
}
|
||||
|
||||
function getShortTypeString(val, diff) {
|
||||
function getShortTypeString(val: any, diff: boolean | undefined) {
|
||||
if (diff && Array.isArray(val)) {
|
||||
val = val[val.length === 2 ? 1 : 0];
|
||||
}
|
||||
|
@ -38,14 +35,21 @@ function getShortTypeString(val, diff) {
|
|||
}
|
||||
}
|
||||
|
||||
function getText(type, data, isWideLayout, isDiff) {
|
||||
function getText(
|
||||
type: string,
|
||||
data: any,
|
||||
isWideLayout: boolean,
|
||||
isDiff: boolean | undefined
|
||||
) {
|
||||
if (type === 'Object') {
|
||||
const keys = Object.keys(data);
|
||||
if (!isWideLayout) return keys.length ? '{…}' : '{}';
|
||||
|
||||
const str = keys
|
||||
.slice(0, 3)
|
||||
.map((key) => `${key}: ${getShortTypeString(data[key], isDiff)}`)
|
||||
.map(
|
||||
(key) => `${key}: ${getShortTypeString(data[key], isDiff) as string}`
|
||||
)
|
||||
.concat(keys.length > 3 ? ['…'] : [])
|
||||
.join(', ');
|
||||
|
||||
|
@ -55,27 +59,27 @@ function getText(type, data, isWideLayout, isDiff) {
|
|||
|
||||
const str = data
|
||||
.slice(0, 4)
|
||||
.map((val) => getShortTypeString(val, isDiff))
|
||||
.map((val: any) => getShortTypeString(val, isDiff))
|
||||
.concat(data.length > 4 ? ['…'] : [])
|
||||
.join(', ');
|
||||
|
||||
return `[${str}]`;
|
||||
return `[${str as string}]`;
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
const getItemString = (
|
||||
styling,
|
||||
type,
|
||||
data,
|
||||
dataTypeKey,
|
||||
isWideLayout,
|
||||
isDiff
|
||||
styling: StylingFunction,
|
||||
type: string,
|
||||
data: any,
|
||||
dataTypeKey: string | undefined,
|
||||
isWideLayout: boolean,
|
||||
isDiff?: boolean
|
||||
) => (
|
||||
<span {...styling('treeItemHint')}>
|
||||
{data[IS_IMMUTABLE_KEY] ? 'Immutable' : ''}
|
||||
{dataTypeKey && data[dataTypeKey] ? data[dataTypeKey] + ' ' : ''}
|
||||
{dataTypeKey && data[dataTypeKey] ? `${data[dataTypeKey] as string} ` : ''}
|
||||
{getText(type, data, isWideLayout, isDiff)}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
export default function getJsonTreeTheme(base16Theme) {
|
||||
import { Base16Theme } from 'base16';
|
||||
import { StylingConfig } from 'react-base16-styling';
|
||||
|
||||
export default function getJsonTreeTheme(
|
||||
base16Theme: Base16Theme
|
||||
): StylingConfig {
|
||||
return {
|
||||
extend: base16Theme,
|
||||
nestedNode: ({ style }, keyPath, nodeType, expanded) => ({
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import jss from 'jss';
|
||||
import jss, { Styles, StyleSheet } from 'jss';
|
||||
import preset from 'jss-preset-default';
|
||||
import { createStyling } from 'react-base16-styling';
|
||||
import rgba from 'hex-rgba';
|
||||
import { Base16Theme } from 'redux-devtools-themes';
|
||||
import inspector from '../themes/inspector';
|
||||
import * as reduxThemes from 'redux-devtools-themes';
|
||||
import * as inspectorThemes from '../themes';
|
||||
|
||||
jss.setup(preset());
|
||||
|
||||
const colorMap = (theme) => ({
|
||||
const colorMap = (theme: Base16Theme) => ({
|
||||
TEXT_COLOR: theme.base06,
|
||||
TEXT_PLACEHOLDER_COLOR: rgba(theme.base06, 60),
|
||||
BACKGROUND_COLOR: theme.base00,
|
||||
|
@ -34,7 +35,12 @@ const colorMap = (theme) => ({
|
|||
ERROR_COLOR: theme.base08,
|
||||
});
|
||||
|
||||
const getSheetFromColorMap = (map) => ({
|
||||
type Color = keyof ReturnType<typeof colorMap>;
|
||||
type ColorMap = {
|
||||
[color in Color]: string;
|
||||
};
|
||||
|
||||
const getSheetFromColorMap = (map: ColorMap) => ({
|
||||
inspector: {
|
||||
display: 'flex',
|
||||
'flex-direction': 'column',
|
||||
|
@ -384,9 +390,9 @@ const getSheetFromColorMap = (map) => ({
|
|||
},
|
||||
});
|
||||
|
||||
let themeSheet;
|
||||
let themeSheet: StyleSheet;
|
||||
|
||||
const getDefaultThemeStyling = (theme) => {
|
||||
const getDefaultThemeStyling = (theme: Base16Theme) => {
|
||||
if (themeSheet) {
|
||||
themeSheet.detach();
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
function deepMapCached(obj, f, ctx, cache) {
|
||||
cache.push(obj);
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(function (val, key) {
|
||||
val = f.call(ctx, val, key);
|
||||
return typeof val === 'object' && cache.indexOf(val) === -1
|
||||
? deepMapCached(val, f, ctx, cache)
|
||||
: val;
|
||||
});
|
||||
} else if (typeof obj === 'object') {
|
||||
const res = {};
|
||||
for (const key in obj) {
|
||||
let val = obj[key];
|
||||
if (val && typeof val === 'object') {
|
||||
val = f.call(ctx, val, key);
|
||||
res[key] =
|
||||
cache.indexOf(val) === -1 ? deepMapCached(val, f, ctx, cache) : val;
|
||||
} else {
|
||||
res[key] = f.call(ctx, val, key);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
export default function deepMap(obj, f, ctx) {
|
||||
return deepMapCached(obj, f, ctx, []);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import { Iterable, fromJS } from 'immutable';
|
||||
import { fromJS, isAssociative } from 'immutable';
|
||||
import isIterable from './isIterable';
|
||||
|
||||
function iterateToKey(obj, key) {
|
||||
function iterateToKey(obj: any, key: string | number) {
|
||||
// maybe there's a better way, dunno
|
||||
let idx = 0;
|
||||
for (let entry of obj) {
|
||||
for (const entry of obj) {
|
||||
if (Array.isArray(entry)) {
|
||||
if (entry[0] === key) return entry[1];
|
||||
} else {
|
||||
|
@ -15,24 +15,28 @@ function iterateToKey(obj, key) {
|
|||
}
|
||||
}
|
||||
|
||||
export default function getInspectedState(state, path, convertImmutable) {
|
||||
export default function getInspectedState<S>(
|
||||
state: S,
|
||||
path: (string | number)[],
|
||||
convertImmutable: boolean
|
||||
): S {
|
||||
state =
|
||||
path && path.length
|
||||
? {
|
||||
[path[path.length - 1]]: path.reduce((s, key) => {
|
||||
? ({
|
||||
[path[path.length - 1]]: path.reduce((s: any, key) => {
|
||||
if (!s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
if (Iterable.isAssociative(s)) {
|
||||
return s.get(key);
|
||||
if (isAssociative(s)) {
|
||||
return s.get(key as number);
|
||||
} else if (isIterable(s)) {
|
||||
return iterateToKey(s, key);
|
||||
}
|
||||
|
||||
return s[key];
|
||||
}, state),
|
||||
}
|
||||
} as S)
|
||||
: state;
|
||||
|
||||
if (convertImmutable) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export default function isIterable(obj) {
|
||||
export default function isIterable(obj: any) {
|
||||
return (
|
||||
obj !== null &&
|
||||
typeof obj === 'object' &&
|
||||
|
|
|
@ -9,7 +9,6 @@ const isProduction = process.env.NODE_ENV === 'production';
|
|||
|
||||
module.exports = {
|
||||
mode: process.env.NODE_ENV || 'development',
|
||||
devtool: 'eval-source-map',
|
||||
entry: isProduction
|
||||
? ['./demo/src/js/index']
|
||||
: [
|
||||
|
@ -21,26 +20,10 @@ module.exports = {
|
|||
path: path.join(__dirname, 'demo/dist'),
|
||||
filename: 'js/bundle.js',
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
template: 'demo/src/index.html',
|
||||
package: pkg,
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
||||
},
|
||||
}),
|
||||
].concat(isProduction ? [] : [new webpack.HotModuleReplacementPlugin()]),
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
test: /\.(js|ts)x?$/,
|
||||
loader: 'babel-loader',
|
||||
include: [
|
||||
path.join(__dirname, 'src'),
|
||||
|
@ -49,6 +32,17 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.jsx'],
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
template: 'demo/src/index.html',
|
||||
package: pkg,
|
||||
}),
|
||||
].concat(isProduction ? [] : [new webpack.HotModuleReplacementPlugin()]),
|
||||
devServer: isProduction
|
||||
? {}
|
||||
: {
|
||||
|
@ -61,4 +55,5 @@ module.exports = {
|
|||
},
|
||||
historyApiFallback: true,
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
};
|
||||
|
|
|
@ -3131,6 +3131,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/hex-rgba@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/hex-rgba/-/hex-rgba-1.0.0.tgz#b2aed2aa9fdd6152b7f0ac5e3733b974d4eba35a"
|
||||
integrity sha512-u3AGV8fjRsDBqY4wOvVWhVCgKDfh2b0h3mux7KPKU1cm/6mJp14OWBINLgBypeBTM89Nm2j+eKQqIoIe7150DA==
|
||||
|
||||
"@types/hoist-non-react-statics@*", "@types/hoist-non-react-statics@^3.3.0":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
|
||||
|
|
Loading…
Reference in New Issue
Block a user