From d16e9debe4a30fc399c85b35606a2ee2a3ff3f29 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Fri, 5 Jan 2018 22:38:01 +0800 Subject: [PATCH 1/9] set docked on init --- src/components/Dock/Dock.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Dock/Dock.js b/src/components/Dock/Dock.js index 5d96633..1106b74 100644 --- a/src/components/Dock/Dock.js +++ b/src/components/Dock/Dock.js @@ -16,7 +16,7 @@ class Dock extends React.Component { node = null state = { - visible: false, + visible: true, width: 500, isResizing: false } From da112745fbeacc86b4b5c1de8d8c15d453dcd3d7 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Fri, 5 Jan 2018 22:51:25 +0800 Subject: [PATCH 2/9] fix typing issue --- examples/cancellable-counter/index.js | 3 ++- src/containers/ActionList/ActionList.js | 1 + src/containers/EffectEntry/EffectEntry.js | 2 +- src/containers/EffectList/EffectList.js | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/cancellable-counter/index.js b/examples/cancellable-counter/index.js index 6b271aa..e3e7045 100644 --- a/examples/cancellable-counter/index.js +++ b/examples/cancellable-counter/index.js @@ -19,7 +19,8 @@ const store = createStore( ) sagaMiddleware.run(rootSaga) sagaMiddleware.run(function* anotherSaga() { - yield taake('SOMETHING') // THIS IS INTENTIONAL. Simulate an error on the devtools + // yield taake('SOMETHING') // THIS IS INTENTIONAL. Simulate an error on the devtools + yield take('SOMETHING') // Try omit the intentional error }) diff --git a/src/containers/ActionList/ActionList.js b/src/containers/ActionList/ActionList.js index a814f83..431226f 100644 --- a/src/containers/ActionList/ActionList.js +++ b/src/containers/ActionList/ActionList.js @@ -21,6 +21,7 @@ class ActionEntry extends React.Component { render() { const {action } = this.props + console.log(action.action.type) return ( diff --git a/src/containers/EffectEntry/EffectEntry.js b/src/containers/EffectEntry/EffectEntry.js index 14c9126..cd2141f 100644 --- a/src/containers/EffectEntry/EffectEntry.js +++ b/src/containers/EffectEntry/EffectEntry.js @@ -109,7 +109,7 @@ export default connect( const effect = state.effectsById[effectId] return { effect, - hasChildren: state.effectsByParentId[effectId] + hasChildren: !!state.effectsByParentId[effectId] } } )(EffectEntry) diff --git a/src/containers/EffectList/EffectList.js b/src/containers/EffectList/EffectList.js index 4628072..b700d12 100644 --- a/src/containers/EffectList/EffectList.js +++ b/src/containers/EffectList/EffectList.js @@ -32,7 +32,7 @@ class EffectList extends React.Component { } isCollapsed = effectId => { - return this.state.collapsedEffects[effectId] + return !!this.state.collapsedEffects[effectId] } collapseEffect = (effectId, collapsed) => { From a6ff66a15de7ba17d71a9477ef0de167f657bf15 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 00:50:45 +0800 Subject: [PATCH 3/9] add basic filtering --- src/components/Effect/Effect.js | 1 - src/components/ListView/ListView.js | 1 + src/containers/ActionList/ActionList.js | 1 - src/containers/EffectEntry/EffectEntry.js | 7 ++++- src/containers/EffectList/EffectList.js | 37 ++++++++++++++++++++++- src/store/reducers.js | 1 + 6 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/components/Effect/Effect.js b/src/components/Effect/Effect.js index a6bb893..b792364 100644 --- a/src/components/Effect/Effect.js +++ b/src/components/Effect/Effect.js @@ -26,7 +26,6 @@ class Effect extends React.Component { const {effect} = this.props const { status, result, error, winner } = effect - let nodes = [] let data diff --git a/src/components/ListView/ListView.js b/src/components/ListView/ListView.js index 4cfdeef..c98bbc5 100644 --- a/src/components/ListView/ListView.js +++ b/src/components/ListView/ListView.js @@ -28,6 +28,7 @@ class ListView extends React.Component { render() { const indent = this.props.indent || DEFAULT_INDENT + console.log(this.props.nodes); return ( { this.props.nodes.map(node => { diff --git a/src/containers/ActionList/ActionList.js b/src/containers/ActionList/ActionList.js index 431226f..a814f83 100644 --- a/src/containers/ActionList/ActionList.js +++ b/src/containers/ActionList/ActionList.js @@ -21,7 +21,6 @@ class ActionEntry extends React.Component { render() { const {action } = this.props - console.log(action.action.type) return ( diff --git a/src/containers/EffectEntry/EffectEntry.js b/src/containers/EffectEntry/EffectEntry.js index cd2141f..d690a76 100644 --- a/src/containers/EffectEntry/EffectEntry.js +++ b/src/containers/EffectEntry/EffectEntry.js @@ -48,9 +48,10 @@ class EffectEntry extends React.Component { onUnpin = () => this.props.onUnpin(-1) render() { - const {effect, collapsed, pinned, hasChildren} = this.props + const {effect, collapsed, pinned, hasChildren, passFilter} = this.props let pinNode + console.log(effect) if(!effect.root) { pinNode = ( pinned @@ -60,6 +61,7 @@ class EffectEntry extends React.Component { } return ( + passFilter ? @@ -88,6 +90,8 @@ class EffectEntry extends React.Component { ) } + : + null ) } } @@ -99,6 +103,7 @@ EffectEntry.propTypes = { collapsed: PropTypes.bool.isRequired, onCollapse: PropTypes.func.isRequired, onSelect: PropTypes.func.isRequired, + passFilter: PropTypes.bool.isRequired, // injected by Redux store effect: PropTypes.object.isRequired, hasChildren: PropTypes.bool.isRequired, diff --git a/src/containers/EffectList/EffectList.js b/src/containers/EffectList/EffectList.js index b700d12..d7ac935 100644 --- a/src/containers/EffectList/EffectList.js +++ b/src/containers/EffectList/EffectList.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import styled, { css } from 'styled-components' import { connect } from 'react-redux' +import { asEffect } from 'redux-saga/utils' import { matchCurrentAction } from '../../store/selectors' import { KEY_ARROW_DOWN, @@ -25,16 +26,49 @@ const cssMatchAction = css` margin-top: -1px; ` +const effectTypes = ['take', 'put', 'fork', 'call', 'cps', 'join', 'cancel'] + class EffectList extends React.Component { state = { - collapsedEffects: {} + collapsedEffects: {}, + filter: { word: 'a', type: undefined } } isCollapsed = effectId => { return !!this.state.collapsedEffects[effectId] } + isFiltered = effectId => { + const { filter } = this.state + + if (!filter.word) return true + + let data = {}, description + const effect = this.props.effectsById[effectId] + + if (effect.root) { + data = { type: 'root', name: effect.effect.saga.name } + } + + else { + effectTypes.forEach(type => { + if (description = asEffect[type](effect.effect)) { + data = { + type, + name: description.pattern + || description.channel + || description.action + || (description.fn && description.fn.name) + } + } + }) + } + + console.log(data) + return data.name && data.name.toLowerCase().includes(filter.word.toLowerCase()) + } + collapseEffect = (effectId, collapsed) => { this.setState(state => ({ collapsedEffects: { @@ -121,6 +155,7 @@ class EffectList extends React.Component { selected={this.props.selectedEffectId === effectId} pinned={this.props.pinnedEffectId === effectId} collapsed={this.isCollapsed(effectId)} + passFilter={this.isFiltered(effectId)} onCollapse={this.collapseEffect} onPin={this.props.onPin} onUnpin={this.props.onUnpin} diff --git a/src/store/reducers.js b/src/store/reducers.js index 2ce1fe6..b75b950 100644 --- a/src/store/reducers.js +++ b/src/store/reducers.js @@ -50,6 +50,7 @@ export function effectsById(state = {}, action) { switch (action.type) { case EFFECT_TRIGGERED: effect = action.effect + console.log(effect) effectId = effect.effectId newState = {...state, [effectId]: { From 3542a8a80a340fe8285b17f2f8c17edcd81ffe4b Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 01:37:14 +0800 Subject: [PATCH 4/9] add styled input filter --- src/containers/EffectEntry/EffectEntry.js | 1 - src/containers/EffectList/EffectList.js | 7 +++---- src/containers/EffectView/EffectView.js | 3 +++ .../SagaMonitorView/SagaMonitorView.js | 17 ++++++++++++++--- src/containers/SagaMonitorView/styles.js | 9 +++++++++ src/store/reducers.js | 1 - 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/containers/EffectEntry/EffectEntry.js b/src/containers/EffectEntry/EffectEntry.js index d690a76..e4a4336 100644 --- a/src/containers/EffectEntry/EffectEntry.js +++ b/src/containers/EffectEntry/EffectEntry.js @@ -51,7 +51,6 @@ class EffectEntry extends React.Component { const {effect, collapsed, pinned, hasChildren, passFilter} = this.props let pinNode - console.log(effect) if(!effect.root) { pinNode = ( pinned diff --git a/src/containers/EffectList/EffectList.js b/src/containers/EffectList/EffectList.js index d7ac935..e264c70 100644 --- a/src/containers/EffectList/EffectList.js +++ b/src/containers/EffectList/EffectList.js @@ -31,8 +31,7 @@ const effectTypes = ['take', 'put', 'fork', 'call', 'cps', 'join', 'cancel'] class EffectList extends React.Component { state = { - collapsedEffects: {}, - filter: { word: 'a', type: undefined } + collapsedEffects: {} } isCollapsed = effectId => { @@ -40,7 +39,7 @@ class EffectList extends React.Component { } isFiltered = effectId => { - const { filter } = this.state + const { filter } = this.props if (!filter.word) return true @@ -65,7 +64,6 @@ class EffectList extends React.Component { }) } - console.log(data) return data.name && data.name.toLowerCase().includes(filter.word.toLowerCase()) } @@ -189,6 +187,7 @@ EffectList.propTypes = { selectedEffectId: PropTypes.number, onSelectionChange: PropTypes.func.isRequired, rootEffectIds: PropTypes.array.isRequired, + filter: PropTypes.object.isRequired, // Injected by redux effectsById: PropTypes.object.isRequired, effectsByParentId: PropTypes.object.isRequired, diff --git a/src/containers/EffectView/EffectView.js b/src/containers/EffectView/EffectView.js index d9ab52b..7f3b909 100644 --- a/src/containers/EffectView/EffectView.js +++ b/src/containers/EffectView/EffectView.js @@ -65,6 +65,7 @@ class EffectView extends React.Component { render() { const rootEffectIds = this.props.rootEffectIds + const filter = this.props.filter const selectedEffectId = this.state.selectedEffectId const pinnedEffectId = this.state.pinnedEffectId @@ -78,6 +79,7 @@ class EffectView extends React.Component { pinnedEffectId={pinnedEffectId} onPin={this.handlePin} onUnpin={this.handleUnpin} + filter={filter} /> @@ -94,6 +96,7 @@ class EffectView extends React.Component { EffectView.propTypes = { rootEffectIds: PropTypes.array.isRequired, + filter: PropTypes.object.isRequired, // Inject by Redux effectsById: PropTypes.object.isRequired } diff --git a/src/containers/SagaMonitorView/SagaMonitorView.js b/src/containers/SagaMonitorView/SagaMonitorView.js index 6a36f91..c26cfbf 100644 --- a/src/containers/SagaMonitorView/SagaMonitorView.js +++ b/src/containers/SagaMonitorView/SagaMonitorView.js @@ -9,7 +9,8 @@ import { SagaMonitorContainer, SagaMonitorHeader, SagaMonitorOption, - SagaMonitorBody + SagaMonitorBody, + FilterEffect } from './styles' const EFFECT_VIEW = 'Effects' @@ -22,7 +23,8 @@ class SagaMonitorView extends React.Component { state = { currentView: EFFECT_VIEW, - currentViewIndex: 0 + currentViewIndex: 0, + filter: { word: '', type: undefined } } viewHandlers = { @@ -30,10 +32,14 @@ class SagaMonitorView extends React.Component { [ACTION_VIEW]: () => this.setState({ currentView: ACTION_VIEW, currentViewIndex: 1 }) } + updateFilter = () => this.setState(({ filter }) => ( + { filter: { ...filter, word: this.filter.value } } + )) + renderCurrentView() { switch (this.state.currentView) { case EFFECT_VIEW: - return + return case ACTION_VIEW: return default: @@ -62,6 +68,11 @@ class SagaMonitorView extends React.Component { {this.renderViewOption(EFFECT_VIEW)} {this.renderViewOption(ACTION_VIEW)} + this.filter = filter} + placeholder="filter..." + />
diff --git a/src/containers/SagaMonitorView/styles.js b/src/containers/SagaMonitorView/styles.js index c391c19..1a22829 100644 --- a/src/containers/SagaMonitorView/styles.js +++ b/src/containers/SagaMonitorView/styles.js @@ -49,3 +49,12 @@ export const SagaMonitorBody = styled.section` bottom: 0; width: 100%; ` + +export const FilterEffect = styled.input` + width: 80px; + margin: 4px 10px; + + &::placeholder { + padding-left: 4px; + } +` diff --git a/src/store/reducers.js b/src/store/reducers.js index b75b950..2ce1fe6 100644 --- a/src/store/reducers.js +++ b/src/store/reducers.js @@ -50,7 +50,6 @@ export function effectsById(state = {}, action) { switch (action.type) { case EFFECT_TRIGGERED: effect = action.effect - console.log(effect) effectId = effect.effectId newState = {...state, [effectId]: { From 8f341a6eebd3aee93370f18375755cd0d81ee36d Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 02:37:54 +0800 Subject: [PATCH 5/9] add filter highlighter --- src/components/Effect/Effect.js | 43 +++++++++++++++++------ src/components/JSValue/JSValue.js | 8 ++--- src/components/ListView/ListView.js | 1 - src/components/SagaValue/SagaValue.js | 4 +-- src/containers/EffectEntry/EffectEntry.js | 5 +-- src/containers/EffectList/EffectList.js | 1 + src/containers/SagaMonitorView/styles.js | 2 +- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/components/Effect/Effect.js b/src/components/Effect/Effect.js index b792364..905bc7b 100644 --- a/src/components/Effect/Effect.js +++ b/src/components/Effect/Effect.js @@ -18,12 +18,23 @@ class Effect extends React.Component { effectId = this.props.effect.effectId + highlightText = (text) => { + const highlight = this.props.filter + // Split on higlight term and include term into parts, ignore case + let parts = text.split(new RegExp(`(${highlight})`, 'gi')); + return { parts.map((part, i) => + + { part } + ) + } ; + } + renderResult(status, result, error, winner) { return } render() { - const {effect} = this.props + const {effect, filter} = this.props const { status, result, error, winner } = effect let nodes = [] @@ -31,7 +42,7 @@ class Effect extends React.Component { if(effect.root) { nodes = nodes.concat( - renderFuncCall(effect.effect.saga, effect.effect.args), + renderFuncCall(effect.effect.saga, effect.effect.args, this.highlightText), this.renderResult(status, result, error) ) } @@ -39,7 +50,11 @@ class Effect extends React.Component { else if((data = asEffect.take(effect.effect))) { nodes = nodes.concat( renderEffectType('take'), - , + , this.renderResult(status, result, error, winner) ) } @@ -47,14 +62,19 @@ class Effect extends React.Component { else if((data = asEffect.put(effect.effect))) { nodes = nodes.concat( renderEffectType('put'), - + ) } else if((data = asEffect.call(effect.effect))) { nodes = nodes.concat( renderEffectType('call'), - renderFuncCall(data.fn, data.args), + renderFuncCall(data.fn, data.args, this.highlightText), this.renderResult(status, result, error, winner) ) } @@ -70,7 +90,7 @@ class Effect extends React.Component { else if((data = asEffect.fork(effect.effect))) { nodes = nodes.concat( renderEffectType('fork'), - renderFuncCall(data.fn, data.args), + renderFuncCall(data.fn, data.args, this.highlightText), this.renderResult(status, result, error, winner) ) } @@ -78,7 +98,7 @@ class Effect extends React.Component { else if((data = asEffect.join(effect.effect))) { nodes = nodes.concat( renderEffectType('join'), - , + , this.renderResult(status, result, error, winner) ) } @@ -86,7 +106,7 @@ class Effect extends React.Component { else if((data = asEffect.cancel(effect.effect))) { nodes = nodes.concat( renderEffectType('cancel'), - , + , ) } @@ -171,13 +191,13 @@ function renderEffectType(type) { ) } -function renderFuncCall(fn, args) { +function renderFuncCall(fn, args, highlighter = val => val) { if(!args.length) { - return {fn.name}() + return {highlighter(fn.name)}() } return [ - {fn.name}(, + {highlighter(fn.name)}(, ...renderFuncArgs(args), ) ] @@ -196,6 +216,7 @@ function renderFuncArgs(args) { Effect.propTypes = { effect: PropTypes.object.isRequired, + filter: PropTypes.string.isRequired, } export default Effect diff --git a/src/components/JSValue/JSValue.js b/src/components/JSValue/JSValue.js index a5ea889..f5e3805 100644 --- a/src/components/JSValue/JSValue.js +++ b/src/components/JSValue/JSValue.js @@ -12,7 +12,7 @@ import { const vnull = const vfuncKeyword = function -function renderValue(value, isIdentifier, label, onlyPrimitive) { +function renderValue(value, isIdentifier, label, renderRaw, onlyPrimitive) { if(value === null || value === undefined) { return vnull @@ -23,7 +23,7 @@ function renderValue(value, isIdentifier, label, onlyPrimitive) { } const type = typeof value - if(type === 'string') { + if(type === 'string' || renderRaw) { if(isIdentifier) { return {value} } else { @@ -65,8 +65,8 @@ function getObjectSummary(obj) { ) } -function JSValue({value, isIdentifier, label}) { - return renderValue(value, isIdentifier, label, false) +function JSValue({value, isIdentifier, label, renderRaw}) { + return renderValue(value, isIdentifier, label, renderRaw, false) } JSValue.propTypes = { diff --git a/src/components/ListView/ListView.js b/src/components/ListView/ListView.js index c98bbc5..4cfdeef 100644 --- a/src/components/ListView/ListView.js +++ b/src/components/ListView/ListView.js @@ -28,7 +28,6 @@ class ListView extends React.Component { render() { const indent = this.props.indent || DEFAULT_INDENT - console.log(this.props.nodes); return ( { this.props.nodes.map(node => { diff --git a/src/components/SagaValue/SagaValue.js b/src/components/SagaValue/SagaValue.js index a56de61..950baae 100644 --- a/src/components/SagaValue/SagaValue.js +++ b/src/components/SagaValue/SagaValue.js @@ -3,7 +3,7 @@ import { is, CHANNEL_END } from 'redux-saga/utils' import JSValue from '../JSValue' import SagaRef from '../../containers/SagaRef' -export default function SagaValue({value, label, isIdentifier}) { +export default function SagaValue({value, label, isIdentifier, highlighted = false}) { if(is.channel(value)) { return {label || 'Channel'} } @@ -11,6 +11,6 @@ export default function SagaValue({value, label, isIdentifier}) { return } else { - return + return } } diff --git a/src/containers/EffectEntry/EffectEntry.js b/src/containers/EffectEntry/EffectEntry.js index e4a4336..589ef14 100644 --- a/src/containers/EffectEntry/EffectEntry.js +++ b/src/containers/EffectEntry/EffectEntry.js @@ -48,7 +48,7 @@ class EffectEntry extends React.Component { onUnpin = () => this.props.onUnpin(-1) render() { - const {effect, collapsed, pinned, hasChildren, passFilter} = this.props + const {effect, collapsed, pinned, hasChildren, passFilter, filter} = this.props let pinNode if(!effect.root) { @@ -71,7 +71,7 @@ class EffectEntry extends React.Component { /> - + { @@ -102,6 +102,7 @@ EffectEntry.propTypes = { collapsed: PropTypes.bool.isRequired, onCollapse: PropTypes.func.isRequired, onSelect: PropTypes.func.isRequired, + filter: PropTypes.string.isRequired, passFilter: PropTypes.bool.isRequired, // injected by Redux store effect: PropTypes.object.isRequired, diff --git a/src/containers/EffectList/EffectList.js b/src/containers/EffectList/EffectList.js index e264c70..7d9cef4 100644 --- a/src/containers/EffectList/EffectList.js +++ b/src/containers/EffectList/EffectList.js @@ -153,6 +153,7 @@ class EffectList extends React.Component { selected={this.props.selectedEffectId === effectId} pinned={this.props.pinnedEffectId === effectId} collapsed={this.isCollapsed(effectId)} + filter={this.props.filter.word} passFilter={this.isFiltered(effectId)} onCollapse={this.collapseEffect} onPin={this.props.onPin} diff --git a/src/containers/SagaMonitorView/styles.js b/src/containers/SagaMonitorView/styles.js index 1a22829..d9e5fb5 100644 --- a/src/containers/SagaMonitorView/styles.js +++ b/src/containers/SagaMonitorView/styles.js @@ -51,7 +51,7 @@ export const SagaMonitorBody = styled.section` ` export const FilterEffect = styled.input` - width: 80px; + width: 100px; margin: 4px 10px; &::placeholder { From cb205894622503fa7d3a0a6bda2380acc2adc697 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 03:11:20 +0800 Subject: [PATCH 6/9] fix bug in filtering, fix highlighter throw error --- src/components/Effect/Effect.js | 25 +++++++++++++++++-------- src/components/JSValue/JSValue.js | 22 ++++++++++++---------- src/components/SagaValue/SagaValue.js | 4 ++-- src/containers/EffectList/EffectList.js | 2 +- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/components/Effect/Effect.js b/src/components/Effect/Effect.js index 905bc7b..160556f 100644 --- a/src/components/Effect/Effect.js +++ b/src/components/Effect/Effect.js @@ -51,9 +51,9 @@ class Effect extends React.Component { nodes = nodes.concat( renderEffectType('take'), , this.renderResult(status, result, error, winner) ) @@ -63,10 +63,9 @@ class Effect extends React.Component { nodes = nodes.concat( renderEffectType('put'), ) } @@ -98,7 +97,12 @@ class Effect extends React.Component { else if((data = asEffect.join(effect.effect))) { nodes = nodes.concat( renderEffectType('join'), - , + , this.renderResult(status, result, error, winner) ) } @@ -106,7 +110,12 @@ class Effect extends React.Component { else if((data = asEffect.cancel(effect.effect))) { nodes = nodes.concat( renderEffectType('cancel'), - , + , ) } @@ -127,7 +136,7 @@ class Effect extends React.Component { else if((data = asEffect.select(effect.effect))) { nodes = nodes.concat( renderEffectType('select'), - renderFuncCall(data.selector, data.args), + renderFuncCall(data.selector, data.args, this.highlightText), this.renderResult(status, result, error, winner) ) } diff --git a/src/components/JSValue/JSValue.js b/src/components/JSValue/JSValue.js index f5e3805..4dd94d2 100644 --- a/src/components/JSValue/JSValue.js +++ b/src/components/JSValue/JSValue.js @@ -12,7 +12,7 @@ import { const vnull = const vfuncKeyword = function -function renderValue(value, isIdentifier, label, renderRaw, onlyPrimitive) { +function renderValue(value, isIdentifier, label, highlighter, onlyPrimitive) { if(value === null || value === undefined) { return vnull @@ -23,11 +23,11 @@ function renderValue(value, isIdentifier, label, renderRaw, onlyPrimitive) { } const type = typeof value - if(type === 'string' || renderRaw) { + if(type === 'string') { if(isIdentifier) { - return {value} + return {highlighter(value)} } else { - return '{value}' + return '{highlighter(value)}' } } if( @@ -35,14 +35,14 @@ function renderValue(value, isIdentifier, label, renderRaw, onlyPrimitive) { type === 'number' || type === 'boolean' ) { - return {String(value)} + return {highlighter(String(value))} } else if(type === 'function') { return ( {vfuncKeyword} - {value.name}() + {highlighter(value.name)}() ) } @@ -52,7 +52,7 @@ function renderValue(value, isIdentifier, label, renderRaw, onlyPrimitive) { {label} } return ( - + ) } } @@ -65,17 +65,18 @@ function getObjectSummary(obj) { ) } -function JSValue({value, isIdentifier, label, renderRaw}) { - return renderValue(value, isIdentifier, label, renderRaw, false) +function JSValue({value, isIdentifier, label, highlighter = val => val}) { + return renderValue(value, isIdentifier, label, highlighter, false) } JSValue.propTypes = { value: PropTypes.any, isIdentifier: PropTypes.bool, label: PropTypes.any, + highlighter: PropTypes.func, } -export function JSObject({data, renderLabel, preview, ignoreLabelClick}) { +export function JSObject({data, renderLabel, preview, ignoreLabelClick, highlighter = val => val}) { const keys = Object.keys(data) if(!keys.length) { return renderLabel ? renderLabel() : '{}' @@ -137,6 +138,7 @@ JSObject.propTypes = { renderLabel: PropTypes.func, preview: PropTypes.any, ignoreLabelClick: PropTypes.bool, + highlighter: PropTypes.func, } export default JSValue diff --git a/src/components/SagaValue/SagaValue.js b/src/components/SagaValue/SagaValue.js index 950baae..a5d1de8 100644 --- a/src/components/SagaValue/SagaValue.js +++ b/src/components/SagaValue/SagaValue.js @@ -3,7 +3,7 @@ import { is, CHANNEL_END } from 'redux-saga/utils' import JSValue from '../JSValue' import SagaRef from '../../containers/SagaRef' -export default function SagaValue({value, label, isIdentifier, highlighted = false}) { +export default function SagaValue({value, label, isIdentifier, highlighter}) { if(is.channel(value)) { return {label || 'Channel'} } @@ -11,6 +11,6 @@ export default function SagaValue({value, label, isIdentifier, highlighted = fal return } else { - return + return } } diff --git a/src/containers/EffectList/EffectList.js b/src/containers/EffectList/EffectList.js index 7d9cef4..091d4ec 100644 --- a/src/containers/EffectList/EffectList.js +++ b/src/containers/EffectList/EffectList.js @@ -64,7 +64,7 @@ class EffectList extends React.Component { }) } - return data.name && data.name.toLowerCase().includes(filter.word.toLowerCase()) + return typeof data.name === 'string' && data.name.toLowerCase().includes(filter.word.toLowerCase()) } collapseEffect = (effectId, collapsed) => { From 0d8d0c894353a9cf1bcfc548fa3bc9325c25fb53 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 15:11:03 +0800 Subject: [PATCH 7/9] add filter by effect type --- src/components/Effect/Effect.js | 26 +++++----- src/containers/EffectList/EffectList.js | 27 ++++++---- src/containers/EffectView/EffectView.js | 6 ++- .../SagaMonitorView/SagaMonitorView.js | 50 +++++++++++++++++-- src/containers/SagaMonitorView/styles.js | 8 +++ 5 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/components/Effect/Effect.js b/src/components/Effect/Effect.js index 160556f..4437b5e 100644 --- a/src/components/Effect/Effect.js +++ b/src/components/Effect/Effect.js @@ -18,15 +18,15 @@ class Effect extends React.Component { effectId = this.props.effect.effectId - highlightText = (text) => { + highlightFilter = (text) => { const highlight = this.props.filter - // Split on higlight term and include term into parts, ignore case - let parts = text.split(new RegExp(`(${highlight})`, 'gi')); - return { parts.map((part, i) => + const parts = text.split(new RegExp(`(${highlight})`, 'gi')) + + return {parts.map((part, i) => - { part } + {part} ) - } ; + } } renderResult(status, result, error, winner) { @@ -42,7 +42,7 @@ class Effect extends React.Component { if(effect.root) { nodes = nodes.concat( - renderFuncCall(effect.effect.saga, effect.effect.args, this.highlightText), + renderFuncCall(effect.effect.saga, effect.effect.args, this.highlightFilter), this.renderResult(status, result, error) ) } @@ -53,7 +53,7 @@ class Effect extends React.Component { , this.renderResult(status, result, error, winner) ) @@ -73,7 +73,7 @@ class Effect extends React.Component { else if((data = asEffect.call(effect.effect))) { nodes = nodes.concat( renderEffectType('call'), - renderFuncCall(data.fn, data.args, this.highlightText), + renderFuncCall(data.fn, data.args, this.highlightFilter), this.renderResult(status, result, error, winner) ) } @@ -89,7 +89,7 @@ class Effect extends React.Component { else if((data = asEffect.fork(effect.effect))) { nodes = nodes.concat( renderEffectType('fork'), - renderFuncCall(data.fn, data.args, this.highlightText), + renderFuncCall(data.fn, data.args, this.highlightFilter), this.renderResult(status, result, error, winner) ) } @@ -101,7 +101,7 @@ class Effect extends React.Component { value={data} isIdentifier={true} label={data.name} - highlighter={this.highlightText} + highlighter={this.highlightFilter} />, this.renderResult(status, result, error, winner) ) @@ -114,7 +114,7 @@ class Effect extends React.Component { value={data} isIdentifier={true} label={data.name} - highlighter={this.highlightText} + highlighter={this.highlightFilter} />, ) } @@ -136,7 +136,7 @@ class Effect extends React.Component { else if((data = asEffect.select(effect.effect))) { nodes = nodes.concat( renderEffectType('select'), - renderFuncCall(data.selector, data.args, this.highlightText), + renderFuncCall(data.selector, data.args, this.highlightFilter), this.renderResult(status, result, error, winner) ) } diff --git a/src/containers/EffectList/EffectList.js b/src/containers/EffectList/EffectList.js index 091d4ec..7904705 100644 --- a/src/containers/EffectList/EffectList.js +++ b/src/containers/EffectList/EffectList.js @@ -26,7 +26,7 @@ const cssMatchAction = css` margin-top: -1px; ` -const effectTypes = ['take', 'put', 'fork', 'call', 'cps', 'join', 'cancel'] +const EFFECT_TYPES = ['take', 'put', 'fork', 'call', 'cps', 'join', 'cancel'] class EffectList extends React.Component { @@ -34,14 +34,18 @@ class EffectList extends React.Component { collapsedEffects: {} } + componentDidMount() { + this.props.setFilterOptions(EFFECT_TYPES, { allCaps: true }) + } + isCollapsed = effectId => { return !!this.state.collapsedEffects[effectId] } - isFiltered = effectId => { + passFilter = effectId => { const { filter } = this.props - if (!filter.word) return true + if (!filter.word && !filter.type) return true let data = {}, description const effect = this.props.effectsById[effectId] @@ -50,21 +54,23 @@ class EffectList extends React.Component { data = { type: 'root', name: effect.effect.saga.name } } - else { - effectTypes.forEach(type => { + else { // Currently only filters those with string data.name + EFFECT_TYPES.forEach(type => { if (description = asEffect[type](effect.effect)) { data = { type, name: description.pattern - || description.channel - || description.action - || (description.fn && description.fn.name) + || description.channel + || description.action + || (description.fn && description.fn.name) } } }) } - return typeof data.name === 'string' && data.name.toLowerCase().includes(filter.word.toLowerCase()) + return typeof data.name === 'string' + && data.name.toLowerCase().includes(filter.word.toLowerCase()) + && (!filter.type || data.type === filter.type) } collapseEffect = (effectId, collapsed) => { @@ -154,7 +160,7 @@ class EffectList extends React.Component { pinned={this.props.pinnedEffectId === effectId} collapsed={this.isCollapsed(effectId)} filter={this.props.filter.word} - passFilter={this.isFiltered(effectId)} + passFilter={this.passFilter(effectId)} onCollapse={this.collapseEffect} onPin={this.props.onPin} onUnpin={this.props.onUnpin} @@ -189,6 +195,7 @@ EffectList.propTypes = { onSelectionChange: PropTypes.func.isRequired, rootEffectIds: PropTypes.array.isRequired, filter: PropTypes.object.isRequired, + setFilterOptions: PropTypes.func.isRequired, // Injected by redux effectsById: PropTypes.object.isRequired, effectsByParentId: PropTypes.object.isRequired, diff --git a/src/containers/EffectView/EffectView.js b/src/containers/EffectView/EffectView.js index 7f3b909..b4ac40a 100644 --- a/src/containers/EffectView/EffectView.js +++ b/src/containers/EffectView/EffectView.js @@ -64,8 +64,8 @@ class EffectView extends React.Component { render() { - const rootEffectIds = this.props.rootEffectIds - const filter = this.props.filter + const {rootEffectIds, filter, setFilterOptions} = this.props + const selectedEffectId = this.state.selectedEffectId const pinnedEffectId = this.state.pinnedEffectId @@ -80,6 +80,7 @@ class EffectView extends React.Component { onPin={this.handlePin} onUnpin={this.handleUnpin} filter={filter} + setFilterOptions={setFilterOptions} /> @@ -97,6 +98,7 @@ class EffectView extends React.Component { EffectView.propTypes = { rootEffectIds: PropTypes.array.isRequired, filter: PropTypes.object.isRequired, + // setFilterOptions: PropTypes.func.isRequired, // Inject by Redux effectsById: PropTypes.object.isRequired } diff --git a/src/containers/SagaMonitorView/SagaMonitorView.js b/src/containers/SagaMonitorView/SagaMonitorView.js index c26cfbf..ca4ba16 100644 --- a/src/containers/SagaMonitorView/SagaMonitorView.js +++ b/src/containers/SagaMonitorView/SagaMonitorView.js @@ -10,7 +10,9 @@ import { SagaMonitorHeader, SagaMonitorOption, SagaMonitorBody, - FilterEffect + FilterEffect, + FilterDropdown, + FilterOption } from './styles' const EFFECT_VIEW = 'Effects' @@ -24,7 +26,8 @@ class SagaMonitorView extends React.Component { state = { currentView: EFFECT_VIEW, currentViewIndex: 0, - filter: { word: '', type: undefined } + filter: { word: '', type: undefined }, + filterOptions: [] } viewHandlers = { @@ -33,13 +36,43 @@ class SagaMonitorView extends React.Component { } updateFilter = () => this.setState(({ filter }) => ( - { filter: { ...filter, word: this.filter.value } } + { filter: { word: this.filterWord.value, type: this.filterType.value } } )) + setFilterOptions = (items, { allCaps }) => { + const options = items.map(item => { + let label, value + + if(typeof item === 'object') { + label = item.option || item.value + value = item.value + } + else if(typeof item === 'string') { + label = item + value = item + } + + if (allCaps) label = label.toUpperCase() + + return { label, value } + + }) + + this.setState({ filterOptions: options }) + } + + renderFilterOptions = () => this.state.filterOptions.map(option => { + return {option.label} + }) + renderCurrentView() { switch (this.state.currentView) { case EFFECT_VIEW: - return + return case ACTION_VIEW: return default: @@ -70,9 +103,16 @@ class SagaMonitorView extends React.Component { {this.renderViewOption(ACTION_VIEW)} this.filter = filter} + innerRef={filter => this.filterWord = filter} placeholder="filter..." /> + this.filterType = filter} + > + none + {this.renderFilterOptions()} +
diff --git a/src/containers/SagaMonitorView/styles.js b/src/containers/SagaMonitorView/styles.js index d9e5fb5..a50b9d1 100644 --- a/src/containers/SagaMonitorView/styles.js +++ b/src/containers/SagaMonitorView/styles.js @@ -58,3 +58,11 @@ export const FilterEffect = styled.input` padding-left: 4px; } ` + +export const FilterDropdown = styled.select` + width: 60px; +` + +export const FilterOption = styled.option` + width: 30px; +` From 76ba7639e0130a5387fa9b79c2beac6109e7664c Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 15:36:18 +0800 Subject: [PATCH 8/9] fix highlighter error in JSValue --- src/components/Effect/Effect.js | 9 +++++++-- src/components/JSValue/JSValue.js | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/Effect/Effect.js b/src/components/Effect/Effect.js index 4437b5e..6afa5cf 100644 --- a/src/components/Effect/Effect.js +++ b/src/components/Effect/Effect.js @@ -21,7 +21,7 @@ class Effect extends React.Component { highlightFilter = (text) => { const highlight = this.props.filter const parts = text.split(new RegExp(`(${highlight})`, 'gi')) - + return {parts.map((part, i) => {part} @@ -66,6 +66,7 @@ class Effect extends React.Component { value={data.channel || data.action} label={data.action.type} isIdentifier={true} + highlighter={this.highlightFilter} /> ) } @@ -144,7 +145,11 @@ class Effect extends React.Component { else if((data = asEffect.actionChannel(effect.effect))) { nodes = nodes.concat( renderEffectType('actionChannel'), - , + , this.renderResult(status, result, error, winner) ) } diff --git a/src/components/JSValue/JSValue.js b/src/components/JSValue/JSValue.js index 4dd94d2..18328f9 100644 --- a/src/components/JSValue/JSValue.js +++ b/src/components/JSValue/JSValue.js @@ -12,7 +12,7 @@ import { const vnull = const vfuncKeyword = function -function renderValue(value, isIdentifier, label, highlighter, onlyPrimitive) { +function renderValue(value, isIdentifier, label, onlyPrimitive, highlighter = val => val) { if(value === null || value === undefined) { return vnull @@ -66,7 +66,7 @@ function getObjectSummary(obj) { } function JSValue({value, isIdentifier, label, highlighter = val => val}) { - return renderValue(value, isIdentifier, label, highlighter, false) + return renderValue(value, isIdentifier, label, false, highlighter) } JSValue.propTypes = { From 9cf9a671c2b5126de68c18d501a5718f33fd6741 Mon Sep 17 00:00:00 2001 From: Albert Lucianto Date: Sat, 6 Jan 2018 16:10:45 +0800 Subject: [PATCH 9/9] revert intentional error --- examples/cancellable-counter/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/cancellable-counter/index.js b/examples/cancellable-counter/index.js index e3e7045..6b271aa 100644 --- a/examples/cancellable-counter/index.js +++ b/examples/cancellable-counter/index.js @@ -19,8 +19,7 @@ const store = createStore( ) sagaMiddleware.run(rootSaga) sagaMiddleware.run(function* anotherSaga() { - // yield taake('SOMETHING') // THIS IS INTENTIONAL. Simulate an error on the devtools - yield take('SOMETHING') // Try omit the intentional error + yield taake('SOMETHING') // THIS IS INTENTIONAL. Simulate an error on the devtools })