Factor out NodeTypeConfig (#763)

This factors `NodeTypeConfig` out of the `WeightConfig` component. The
scope for a `NodeTypeConfig` is that it configures a single node type.
Right now it just renders a single `WeightSlider`, but I like factoring
out both for consistency with the `EdgeTypeConfig` (see #749) and
because I expect we may want to add more complexity later.

Test plan: The new component has some tests, also I manually tested the
frontend.
This commit is contained in:
Dandelion Mané 2018-09-04 12:52:53 -07:00 committed by GitHub
parent 44407b5520
commit 4cd45c77fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 108 additions and 38 deletions

View File

@ -6,9 +6,14 @@ import sortBy from "lodash.sortby";
import {type EdgeEvaluator} from "../../core/attribution/pagerank";
import {byEdgeType, byNodeType} from "./edgeWeights";
import {defaultStaticAdapters} from "../adapters/defaultPlugins";
import type {NodeType, EdgeType} from "../adapters/pluginAdapter";
import type {EdgeType} from "../adapters/pluginAdapter";
import {WeightSlider} from "./weights/WeightSlider";
import {DirectionalitySlider} from "./weights/DirectionalitySlider";
import {
NodeTypeConfig,
defaultWeightedNodeType,
type WeightedNodeType,
} from "./weights/NodeTypeConfig";
type Props = {|
+onChange: (EdgeEvaluator) => void,
@ -28,19 +33,9 @@ const defaultEdgeWeights = (): EdgeWeights => {
return result;
};
type NodeWeights = WeightedNodeType[];
type WeightedNodeType = {|+type: NodeType, +weight: number|};
const defaultNodeWeights = (): NodeWeights => {
const result = [];
for (const type of defaultStaticAdapters().nodeTypes()) {
result.push({type, weight: type.defaultWeight});
}
return result;
};
type State = {
edgeWeights: EdgeWeights,
nodeWeights: NodeWeights,
nodeWeights: $ReadOnlyArray<WeightedNodeType>,
expanded: boolean,
};
@ -49,7 +44,9 @@ export class WeightConfig extends React.Component<Props, State> {
super(props);
this.state = {
edgeWeights: defaultEdgeWeights(),
nodeWeights: defaultNodeWeights(),
nodeWeights: defaultStaticAdapters()
.nodeTypes()
.map(defaultWeightedNodeType),
expanded: false,
};
}
@ -175,36 +172,30 @@ class EdgeConfig extends React.Component<{
}
class NodeConfig extends React.Component<{
nodeWeights: NodeWeights,
onChange: (NodeWeights) => void,
nodeWeights: $ReadOnlyArray<WeightedNodeType>,
onChange: ($ReadOnlyArray<WeightedNodeType>) => void,
}> {
render() {
const sortedWeights = sortBy(
this.props.nodeWeights,
({type}) => type.prefix
);
const controls = sortedWeights.map(({type, weight}) => {
const onChange = (value) => {
const nodeWeights = this.props.nodeWeights.filter(
(x) => x.type.prefix !== type.prefix
_renderControls() {
return sortBy(this.props.nodeWeights, ({type}) => type.prefix).map(
(weightedType) => {
const onChange = (newType) => {
const nodeWeights = this.props.nodeWeights.filter(
(x) => x.type.prefix !== weightedType.type.prefix
);
nodeWeights.push(newType);
this.props.onChange(nodeWeights);
};
return (
<NodeTypeConfig weightedType={weightedType} onChange={onChange} />
);
nodeWeights.push({type, weight: value});
this.props.onChange(nodeWeights);
};
return (
<WeightSlider
key={type.prefix}
weight={weight}
name={type.name}
onChange={onChange}
/>
);
});
}
);
}
render() {
return (
<div>
<h2>Node weights</h2>
{controls}
{this._renderControls()}
</div>
);
}

View File

@ -0,0 +1,34 @@
// @flow
import React from "react";
import {WeightSlider} from "./WeightSlider";
import {type NodeType} from "../../adapters/pluginAdapter";
export type WeightedNodeType = {|+type: NodeType, +weight: number|};
export function defaultWeightedNodeType(type: NodeType): WeightedNodeType {
return {
type,
weight: type.defaultWeight,
};
}
export class NodeTypeConfig extends React.Component<{
+weightedType: WeightedNodeType,
+onChange: (WeightedNodeType) => void,
}> {
render() {
return (
<WeightSlider
name={this.props.weightedType.type.name}
weight={this.props.weightedType.weight}
onChange={(weight) => {
this.props.onChange({
...this.props.weightedType,
weight,
});
}}
/>
);
}
}

View File

@ -0,0 +1,45 @@
// @flow
import React from "react";
import {shallow} from "enzyme";
import {WeightSlider} from "./WeightSlider";
import {defaultWeightedNodeType, NodeTypeConfig} from "./NodeTypeConfig";
import {inserterNodeType} from "../../adapters/demoAdapters";
require("../../testUtil").configureEnzyme();
describe("app/credExplorer/weights/NodeTypeConfig", () => {
describe("defaultWeightedNodeType", () => {
it("sets default weight as specified in type", () => {
const wnt = defaultWeightedNodeType(inserterNodeType);
expect(wnt.weight).toEqual(wnt.type.defaultWeight);
});
});
describe("NodeTypeConfig", () => {
function example() {
const onChange = jest.fn();
const wnt = {
type: inserterNodeType,
weight: 0.125,
};
const element = shallow(
<NodeTypeConfig onChange={onChange} weightedType={wnt} />
);
const slider = element.find(WeightSlider);
return {onChange, wnt, slider};
}
it("sets up the weight slider", () => {
const {wnt, slider} = example();
expect(slider.props().name).toBe(wnt.type.name);
expect(slider.props().weight).toBe(wnt.weight);
});
it("weight slider onChange works", () => {
const {wnt, slider, onChange} = example();
slider.props().onChange(9);
const updated = {...wnt, weight: 9};
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange.mock.calls[0][0]).toEqual(updated);
});
});
});