Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 59 additions & 17 deletions examples/demo-app.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,100 @@
var { selectorGraph } = ReselectTools;
var { createSelector } = Reselect;
ReselectTools.getStateWith(() => STORE);

var STORE = {
data: {
users: {
'1': {
id: '1',
'bob': {
id: 'bob',
name: 'bob',
pets: ['a', 'b'],
age: 24,
pets: ['fluffy', 'paws'],
},
'2': {
id: '2',
'alice': {
id: 'alice',
name: 'alice',
pets: ['a'],
age: 22,
pets: ['fluffy'],
}
},
pets: {
'a': {
'fluffy': {
name: 'fluffy',
},
'b': {
'paws': {
name: 'paws',
}
}
},
ui: {
currentUser: '1',
currentUser: 'alice',
}
};

const data$ = (state) => state.data;
const ui$ = (state) => state.ui;
var users$ = createSelector(data$, (data) => data.users);
var pets$ = createSelector(data$, ({ pets }) => pets);
var currentUser$ = createSelector(ui$, users$, (ui, users) => users[ui.currentUser]);
const users$ = (state) => state.data.users;
const pets$ = (state) => state.data.pets;
const currentUser$ = createSelector(ui$, users$, (ui, users) => users[ui.currentUser]);

var currentUserPets$ = createSelector(currentUser$, pets$, (currentUser, pets) => currentUser.pets.map((petId) => pets[petId]));
const currentUserPets$ = createSelector(currentUser$, pets$, (currentUser, pets) => currentUser.pets.map((petId) => pets[petId]));
const currentUserAge$ = createSelector(currentUser$, (currentUser) => currentUser.age);

const random$ = (state) => 1;
const thingy$ = createSelector(random$, (number) => number + 1);

const selectors = {
data$,
ui$,
users$,
pets$,
currentUser$,
currentUserPets$,
currentUserAge$,
random$,
thingy$,
};

ReselectTools.registerSelectors(selectors);
ReselectTools.getStateWith(() => STORE);


drawCytoscapeGraph(selectorGraph());
update();

function update() {
const currentUserDiv = document.getElementById('current-user');
selectorGraph();
currentUserDiv.innerHTML = `Current User: ${currentUser$(STORE).name}.`;
}

document.addEventListener('DOMContentLoaded', () => {
const updateBobAge = () => {
STORE = Object.assign({}, STORE, {
data: Object.assign({}, STORE.data, {
users: Object.assign({}, STORE.data.users, {
bob: Object.assign({}, STORE.data.users.bob, {
age: STORE.data.users.bob.age + 1
})
})
})
});

update();
};

const updateAliceAge = () => {
STORE = Object.assign({}, STORE, {
data: Object.assign({}, STORE.data, {
users: Object.assign({}, STORE.data.users, {
alice: Object.assign({}, STORE.data.users.alice, {
age: STORE.data.users.alice.age + 1
})
})
})
});

update();
};

drawCytoscapeGraph(selectorGraph());
document.getElementById('incr-bob-age').addEventListener('click', updateBobAge);
document.getElementById('incr-alice-age').addEventListener('click', updateAliceAge);
});
17 changes: 15 additions & 2 deletions examples/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
height: 90vh;
}

#info {
position: absolute;
bottom: 0;
left: 0;
background: white;
display: inline-block;
}

</style>
</head>
<body>
Expand All @@ -16,8 +24,13 @@
<script src="https://cdn.rawgit.com/cpettitt/dagre/v0.7.4/dist/dagre.min.js"></script>

<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/master/cytoscape-dagre.js"></script>
<script src="https://unpkg.com/reselect-tools/dist/reselect-tools.js"></script>

<script src="../dist/reselect-tools.js"></script>
<div id="info">
<span>Note that downstream selectors only recompute when you increment the <em>current user's</em> age.</span><br/>
<span id="current-user"></span>
<button id="incr-bob-age">Increase user Bobs's age</button>
<button id="incr-alice-age">Increase user Alice's age</button>
</div>
<script src="./simple-graph.js"></script>
<script src="./demo-app.js"></script>
</body>
Expand Down
1 change: 1 addition & 0 deletions extension/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"jsx-a11y/no-static-element-interactions": 0,
"jsx-a11y/label-has-for": 0,
"no-param-reassign": 0,
"consistent-return": 0,
"comma-dangle": 0,
"spaced-comment": 0,
Expand Down
4 changes: 2 additions & 2 deletions extension/app/actions/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ export function getSelectorGraphSuccess(graph) {
return { type: types.GET_SELECTOR_GRAPH_SUCCESS, payload: { graph } };
}

export function getSelectorGraph() {
return { type: types.GET_SELECTOR_GRAPH };
export function getSelectorGraph(resetRecomputations = false) {
return { type: types.GET_SELECTOR_GRAPH, payload: { resetRecomputations }};
}
37 changes: 27 additions & 10 deletions extension/app/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { Component, PropTypes } from 'react';
import Button from 'remotedev-app/lib/components/Button';
import MdHelp from 'react-icons/lib/md/help';
import FindReplace from 'react-icons/lib/md/find-replace';
import Clear from 'react-icons/lib/md/clear';
import RefreshIcon from 'react-icons/lib/md/refresh';
import styles from 'remotedev-app/lib/styles';

Expand All @@ -18,13 +19,18 @@ const headerStyles = {
color: 'white',
outline: 'none',
},
helpButton: {
flexGrow: 0,
maxWidth: '40px',
},
};

class NumberButton extends Component {
static propTypes = {
defaultValue: PropTypes.number,
onClick: PropTypes.func,
numbers: PropTypes.array.isRequired,
children: PropTypes.node.isRequired,
}
constructor(props) {
super(props);
Expand All @@ -37,12 +43,9 @@ class NumberButton extends Component {
this.setState({ value: e.target.value.toString() });
e.stopPropagation();
}
onClickWithNumber(e) {
onClickWithNumber() {
this.props.onClick(parseInt(this.state.value, 10));
}
stopPropagation(e) {
e.stopPropagation();
}
render() {
const { numbers, children, ...other } = this.props;
const { value } = this.state;
Expand All @@ -68,18 +71,26 @@ class NumberButton extends Component {
}


export default function Header({ onRefresh, onHelp, onPaintWorst }) {
export default function Header({
onRefresh,
onResetRecomputations,
onHelp,
onPaintWorst,
supportsRefreshRecomputations,
}) {
return (
<header style={styles.buttonBar}>
<Button
style={headerStyles.refreshButton}
Icon={RefreshIcon}
onClick={onRefresh}
>Refresh Selector Graph</Button>
<Button
Icon={MdHelp}
onClick={onHelp}
>Help</Button>
{ supportsRefreshRecomputations ?
<Button
Icon={Clear}
onClick={onResetRecomputations}
>Reset Recomputations</Button> : null
}
<NumberButton
Icon={FindReplace}
onClick={onPaintWorst}
Expand All @@ -88,7 +99,11 @@ export default function Header({ onRefresh, onHelp, onPaintWorst }) {
<span>Select</span>
<span>Most Recomputed</span>
</NumberButton>

<Button
style={headerStyles.helpButton}
Icon={MdHelp}
onClick={onHelp}
/>
</header>
);
}
Expand All @@ -97,4 +112,6 @@ Header.propTypes = {
onRefresh: PropTypes.func,
onHelp: PropTypes.func,
onPaintWorst: PropTypes.func,
onResetRecomputations: PropTypes.func,
supportsRefreshRecomputations: PropTypes.bool
};
2 changes: 1 addition & 1 deletion extension/app/components/StateTree.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import JSONTree from 'react-json-tree';
import React, { PropTypes } from 'react';

const shouldExpandNode = (keyName, data, level) => false;
const shouldExpandNode = (keyName, data, level) => level === 0;

const isObject = o => typeof o === 'object';

Expand Down
49 changes: 20 additions & 29 deletions extension/app/containers/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import Header from '../components/Header';

import * as SelectorActions from '../actions/graph';

import {
supportsRefreshRecomputations$,
checkedSelector$
} from '../selectors/selectors';

const contentStyles = {
content: {
Expand Down Expand Up @@ -48,46 +52,23 @@ function renderMessage(message) {


function openGitRepo() {
const url = 'https://github.com/skortchmark9/reselect-devtools-extension';
const url = 'https://github.com/skortchmark9/reselect-tools';
window.open(url, '_blank');
}

const checkedSelector$ = (state) => {
const { checkedSelectorId, nodes, edges } = state.graph;
const selector = nodes[checkedSelectorId];
if (!selector) return;

// this is a bit ugly because it relies on edges being in order.
const dependencies = edges.filter(edge => edge.from === checkedSelectorId);
const dependencyIds = dependencies.map(edge => edge.to);

if (!selector.inputs) {
return selector;
}

const { inputs } = selector;
if (dependencyIds.length !== inputs.length) {
console.error(`Uh oh, inputs and edges out of sync on ${checkedSelectorId}`);
}

const zipped = [];
for (let i = 0; i < dependencyIds.length; i++) {
zipped.push([dependencyIds[i], inputs[i]]);
}
return { ...selector, zipped };
};


const RecomputationsTotal = ({ nodes }) => {
const nodeArr = Object.keys(nodes).map(k => nodes[k]);
const total = nodeArr.reduce((acc, node) => acc + node.recomputations, 0);
return <h2 style={contentStyles.recomputations}>{total} Recomputations</h2>;
};


@connect(
state => ({
graph: state.graph,
checkedSelector: checkedSelector$(state),
supportsRefreshRecomputations: supportsRefreshRecomputations$(state),
}),
dispatch => ({
actions: bindActionCreators(SelectorActions, dispatch)
Expand All @@ -99,6 +80,7 @@ export default class App extends Component {
actions: PropTypes.object.isRequired,
graph: PropTypes.object,
checkedSelector: PropTypes.object,
supportsRefreshRecomputations: PropTypes.bool,
};

constructor(props) {
Expand All @@ -110,18 +92,25 @@ export default class App extends Component {
this.refreshGraph = this.refreshGraph.bind(this);
this.toggleDock = this.toggleDock.bind(this);
this.paintNWorst = this.paintNWorst.bind(this);
this.resetRecomputations = this.resetRecomputations.bind(this);
}

componentDidMount() {
this.refreshGraph();
}

refreshGraph() {
this.baseRefreshGraph(false);
}
baseRefreshGraph(resetRecomputations) {
this.sg && this.sg.reset();
this.resetSelectorData();
this.props.actions.getSelectorGraph();
}
this.props.actions.getSelectorGraph(resetRecomputations);

}
resetRecomputations() {
this.baseRefreshGraph(true);
}
paintNWorst(n) {
this.resetSelectorData();
this.sg.highlightNMostRecomputed(n);
Expand Down Expand Up @@ -172,7 +161,7 @@ export default class App extends Component {
<SelectorGraph
checkSelector={this.handleCheckSelector}
selector={checkedSelector}
ref={sg => this.sg = sg}
ref={(sg) => { this.sg = sg; }}
{...graph}
/>
</div>
Expand All @@ -194,6 +183,8 @@ export default class App extends Component {
onRefresh={this.refreshGraph}
onHelp={openGitRepo}
onPaintWorst={this.paintNWorst}
onResetRecomputations={this.resetRecomputations}
supportsRefreshRecomputations={this.props.supportsRefreshRecomputations}
/>
{ this.renderContent() }
</div>
Expand Down
6 changes: 5 additions & 1 deletion extension/app/reducers/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { combineReducers } from 'redux';
import graph from './graph';

const identity = (x = null) => x;

export default combineReducers({
graph
graph,
// we provide this so combineReducers doesnt complain about initial state
version: identity,
});
Loading