Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Add RelayPlugin #200

Merged
merged 15 commits into from
Sep 22, 2015
15 changes: 12 additions & 3 deletions agent/Bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class Bridge {
});
}

call(name: string, args: any | Array<any>, cb: (val: any) => any) {
call(name: string, args: Array<any>, cb: (val: any) => any) {
var _cid = this._cid++;
this._cbs.set(_cid, cb);

Expand Down Expand Up @@ -187,11 +187,20 @@ class Bridge {
});
}

setInspectable(id: string, data: Object) {
var prev = this._inspectables.get(id);
if (!prev) {
this._inspectables.set(id, data);
return;
}
this._inspectables.set(id, {...prev, ...data});
}

sendOne(evt: string, data: any) {
var cleaned = [];
var san = dehydrate(data, cleaned);
if (cleaned.length) {
this._inspectables.set(data.id, data);
this.setInspectable(data.id, data);
}
this._wall.send({type: 'event', evt, data: san, cleaned});
}
Expand All @@ -218,7 +227,7 @@ class Bridge {
var cleaned = [];
var san = dehydrate(data, cleaned);
if (cleaned.length) {
this._inspectables.set(data.id, data);
this.setInspectable(data.id, data);
}
return {type: 'event', evt, data: san, cleaned};
});
Expand Down
5 changes: 2 additions & 3 deletions frontend/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Container extends React.Component {
store: Object
) => ?Array<MenuItem>,
},
extraTabs: {[key: string]: () => ReactElement},
};

render(): ReactElement {
Expand All @@ -50,9 +51,7 @@ class Container extends React.Component {
};
return (
<div style={styles.container}>
<TabbedPane
tabs={tabs}
/>
<TabbedPane tabs={tabs} />
<ContextMenu itemSources={[DEFAULT_MENU_ITEMS, this.props.menuItems]} />
</div>
);
Expand Down
30 changes: 25 additions & 5 deletions frontend/DataView/DataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@
*/
'use strict';

import type {DOMEvent} from '../types';

var React = require('react');
var Simple = require('./Simple');

var assign = require('object-assign');
var consts = require('../../agent/consts');
var previewComplex = require('./previewComplex');

class DataView extends React.Component {
props: {
data: Object,
path: Array<string>,
inspect: () => void,
showMenu: () => void,
inspect: (path: Array<string>, cb: () => void) => void,
showMenu: (e: DOMEvent, val: any, path: Array<string>, name: string) => void,
startOpen: boolean,
noSort?: boolean,
readOnly: boolean,
};

Expand All @@ -31,7 +36,9 @@ class DataView extends React.Component {
return <div style={styles.missing}>null</div>;
}
var names = Object.keys(data);
names.sort();
if (!this.props.noSort) {
names.sort();
}
var path = this.props.path;
if (!names.length) {
return <span style={styles.empty}>Empty object</span>;
Expand All @@ -44,6 +51,7 @@ class DataView extends React.Component {
name={'__proto__'}
path={path.concat(['__proto__'])}
key={'__proto__'}
startOpen={this.props.startOpen}
inspect={this.props.inspect}
showMenu={this.props.showMenu}
readOnly={this.props.readOnly}
Expand All @@ -55,6 +63,7 @@ class DataView extends React.Component {
name={name}
path={path.concat([name])}
key={name}
startOpen={this.props.startOpen}
inspect={this.props.inspect}
showMenu={this.props.showMenu}
readOnly={this.props.readOnly}
Expand All @@ -69,7 +78,13 @@ class DataView extends React.Component {
class DataItem extends React.Component {
constructor(props) {
super(props);
this.state = {open: false, loading: false};
this.state = {open: this.props.startOpen, loading: false};
}

componentDidMount() {
if (this.state.open && this.props.value && this.props.value[consts.inspected] === false) {
this.inspect();
}
}

componentWillReceiveProps(nextProps) {
Expand Down Expand Up @@ -157,7 +172,8 @@ class DataItem extends React.Component {
<div style={styles.head}>
{opener}
<div
style={styles.name}
style={assign({}, styles.name, complex && styles.complexName)}
onClick={this.toggleOpen.bind(this)}
>
{this.props.name}:
</div>
Expand Down Expand Up @@ -218,6 +234,10 @@ var styles = {
margin: '2px 3px',
},

complexName: {
cursor: 'pointer',
},

preview: {
display: 'flex',
margin: '2px 3px',
Expand Down
2 changes: 1 addition & 1 deletion frontend/DataView/Simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ Simple.propTypes = {
};

Simple.contextTypes = {
onChange: React.PropTypes.func.isRequired,
onChange: React.PropTypes.func,
};

var styles = {
Expand Down
25 changes: 19 additions & 6 deletions frontend/Panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ var Container = require('./Container');
var Store = require('./Store');
var keyboardNav = require('./keyboardNav');
var invariant = require('./invariant');
var assign = require('object-assign');

var Bridge = require('../agent/Bridge');
var NativeStyler = require('../plugins/ReactNativeStyle/ReactNativeStyle.js');
var RelayPlugin = require('../plugins/Relay/RelayPlugin');

var consts = require('../agent/consts');

Expand All @@ -44,7 +46,7 @@ class Panel extends React.Component {
_keyListener: ?(e: DOMEvent) => void;
_checkTimeout: ?number;
_unMounted: boolean;
_bridge: ?Bridge;
_bridge: Bridge;
_store: Store;
_unsub: ?() => void;

Expand All @@ -55,6 +57,7 @@ class Panel extends React.Component {
this.state = {loading: true, isReact: this.props.alreadyFoundReact};
this._unMounted = false;
window.panel = this;
this.plugins = [];
}

getChildContext(): Object {
Expand Down Expand Up @@ -141,6 +144,8 @@ class Panel extends React.Component {
}

teardown() {
this.plugins.forEach(p => p.teardown());
this.plugins = [];
if (this._keyListener) {
window.removeEventListener('keydown', this._keyListener);
this._keyListener = null;
Expand All @@ -152,7 +157,6 @@ class Panel extends React.Component {
this._teardownWall();
this._teardownWall = null;
}
this._bridge = null;
}

inject() {
Expand All @@ -161,13 +165,16 @@ class Panel extends React.Component {

this._bridge = new Bridge(wall);

if (this._bridge) {
this._store = new Store(this._bridge);
}
this._store = new Store(this._bridge);
var refresh = () => this.forceUpdate();
this.plugins = [
new RelayPlugin(this._store, this._bridge, refresh),
];
this._keyListener = keyboardNav(this._store, window);

window.addEventListener('keydown', this._keyListener);


this._store.on('connected', () => {
this.setState({loading: false});
this.getNewSelection();
Expand Down Expand Up @@ -211,6 +218,11 @@ class Panel extends React.Component {
if (!this.state.isReact) {
return <div style={styles.loading}><h1>Looking for react...</h1></div>;
}
var extraTabs = assign.apply(null, [{}].concat(this.plugins.map(p => p.tabs())));
var extraPanes = [].concat(...this.plugins.map(p => p.panes()));
if (this._store.capabilities.rnStyle) {
extraPanes.push(panelRNStyle(this._bridge));
}
return (
<Container
reload={this.props.reload && this.reload.bind(this)}
Expand Down Expand Up @@ -239,7 +251,8 @@ class Panel extends React.Component {
}];
},
}}
extraPanes={this._store.capabilities.rnStyle && [panelRNStyle(this._bridge)]}
extraPanes={extraPanes}
extraTabs={extraTabs}
/>
);
}
Expand Down
11 changes: 9 additions & 2 deletions frontend/SplitPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,16 @@ var React = require('react');
var Draggable = require('./Draggable');
var assign = require('object-assign');

type Props = {
style: ?{[key: string]: any},
left: () => ReactElement,
right: () => ReactElement,
initialWidth: number,
};

class SplitPane extends React.Component {
constructor(props: Object) {
props: Props;
constructor(props: Props) {
super(props);
this.state = {
width: props.initialWidth,
Expand Down Expand Up @@ -59,7 +67,6 @@ class SplitPane extends React.Component {
var styles = {
container: {
display: 'flex',
fontFamily: 'sans-serif',
minWidth: 0,
flex: 1,
},
Expand Down
10 changes: 9 additions & 1 deletion frontend/TabbedPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class TabbedPane extends React.Component {
style = assign({}, style, styles.lastTab);
}
return (
<li style={style} onClick={() => this.props.setSelectedTab(name)}>
<li key={name + i} style={style} onClick={() => this.props.setSelectedTab(name)}>
{name}
</li>
);
Expand Down Expand Up @@ -90,6 +90,14 @@ var styles = {

module.exports = decorate({
listeners: () => ['selectedTab'],
shouldUpdate: (props, prevProps) => {
for (var name in props) {
if (props[name] !== prevProps[name]) {
return true;
}
}
return false;
},
props(store) {
return {
selected: store.selectedTab,
Expand Down
24 changes: 13 additions & 11 deletions frontend/decorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type Options = {
* }, MyComp);
*/
module.exports = function(options: Options, Component: any): any {
var storeKey = options.store || 'store';
class Wrapper extends React.Component {
_listeners: Array<string>;
_update: () => void;
Expand All @@ -61,25 +62,25 @@ module.exports = function(options: Options, Component: any): any {
}

componentWillMount() {
if (!this.context.store) {
if (!this.context[storeKey]) {
return console.warn('no store on context...');
}
this._update = () => this.forceUpdate();
if (!options.listeners) {
return undefined;
}
this._listeners = options.listeners(this.props, this.context.store);
this._listeners = options.listeners(this.props, this.context[storeKey]);
this._listeners.forEach(evt => {
this.context.store.on(evt, this._update);
this.context[storeKey].on(evt, this._update);
});
}

componentWillUnmount() {
if (!this.context.store) {
if (!this.context[storeKey]) {
return console.warn('no store on context...');
}
this._listeners.forEach(evt => {
this.context.store.off(evt, this._update);
this.context[storeKey].off(evt, this._update);
});
}

Expand All @@ -94,32 +95,33 @@ module.exports = function(options: Options, Component: any): any {
}

componentWillUpdate(nextProps, nextState) {
if (!this.context.store) {
if (!this.context[storeKey]) {
return console.warn('no store on context...');
}
if (!options.listeners) {
return undefined;
}
var listeners = options.listeners(this.props, this.context.store);
var listeners = options.listeners(this.props, this.context[storeKey]);
var diff = arrayDiff(listeners, this._listeners);
diff.missing.forEach(name => {
this.context.store.off(name, this._update);
this.context[storeKey].off(name, this._update);
});
diff.newItems.forEach(name => {
this.context.store.on(name, this._update);
this.context[storeKey].on(name, this._update);
});
this._listeners = listeners;
}

render() {
var store = this.context.store;
var store = this.context[storeKey];
var props = store && options.props(store, this.props);
return <Component {...props} {...this.props} />;
}
}

Wrapper.contextTypes = {
store: React.PropTypes.object,
// $FlowFixMe computed property
[storeKey]: React.PropTypes.object,
};

Wrapper.displayName = 'Wrapper(' + Component.name + ')';
Expand Down
Loading