Allow editing artifact descriptions (#114)

Summary:
It looks like this:
![Screenshot](https://user-images.githubusercontent.com/4317806/37943962-a8352b94-312e-11e8-9523-855a34020709.png)

Test Plan:
Interaction tests included. Run `yarn test`.

wchargin-branch: artifact-descriptions
This commit is contained in:
William Chargin 2018-03-26 20:11:30 -07:00 committed by GitHub
parent 99f24c420a
commit f93c9a8e42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 32 deletions

View File

@ -50,24 +50,66 @@ export class ArtifactGraphEditor extends React.Component<Props, State> {
);
}
updateArtifactDescription(
oldArtifactNode: Node<NodePayload>,
newDescription: string
): void {
this.setState(
(state) => ({
graph: state.graph
.copy()
.removeNode(oldArtifactNode.address)
.addNode({
address: oldArtifactNode.address,
payload: {
name: oldArtifactNode.payload.name,
description: newDescription,
},
}),
}),
() => {
this.props.onChange(this.state.graph);
}
);
}
render() {
return (
<div>
<h2>Artifacts</h2>
<ul>
{this.state.graph
.getAllNodes()
.map((x) => <li key={x.address.id}>{x.payload.name}</li>)}
<input
value={this.state.artifactInProgressName}
onChange={(e) => {
const value = e.target.value;
this.setState((state) => ({
artifactInProgressName: value,
}));
}}
/>
</ul>
<table>
<thead>
<tr>
<th>Artifact</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{this.state.graph.getAllNodes().map((x) => (
<tr key={x.address.id}>
<td>{x.payload.name}</td>
<td>
<textarea
key={`description-${x.address.id}`}
value={x.payload.description}
onChange={(e) => {
this.updateArtifactDescription(x, e.target.value);
}}
/>
</td>
</tr>
))}
</tbody>
</table>
<input
value={this.state.artifactInProgressName}
onChange={(e) => {
const value = e.target.value;
this.setState((state) => ({
artifactInProgressName: value,
}));
}}
/>
<button
onClick={() => {
this.addArtifact(this.state.artifactInProgressName);

View File

@ -13,9 +13,8 @@ require("./testUtil").configureAphrodite();
require("./testUtil").configureEnzyme();
describe("ArtifactGraphEditor", () => {
it("adds an artifact to the list", () => {
const onChange = jest.fn();
const component = (
function createComponent(onChange) {
return (
<ArtifactGraphEditor
settings={{
githubApiToken: "123youdontneedme",
@ -25,9 +24,19 @@ describe("ArtifactGraphEditor", () => {
onChange={onChange}
/>
);
}
it("invokes its callback after mounting, not construction", () => {
const onChange = jest.fn();
const component = createComponent(onChange);
expect(onChange).not.toHaveBeenCalled();
const element = shallow(component);
shallow(component);
expect(onChange).toHaveBeenCalledTimes(1);
});
it("adds an artifact to the list", () => {
const onChange = jest.fn();
const element = shallow(createComponent(onChange));
expect(onChange).toHaveBeenLastCalledWith(new Graph());
element
.find("input")
@ -35,7 +44,7 @@ describe("ArtifactGraphEditor", () => {
expect(onChange).toHaveBeenCalledTimes(1);
element.find("button").simulate("click");
expect(
element.find("li").filterWhere((x) => x.text() === "Root artifact!")
element.find("td").filterWhere((x) => x.text() === "Root artifact!")
).toHaveLength(1);
expect(onChange).toHaveBeenCalledTimes(2);
expect(onChange).toHaveBeenLastCalledWith(
@ -54,28 +63,53 @@ describe("ArtifactGraphEditor", () => {
);
});
it("modifies an artifact's description", () => {
const onChange = jest.fn();
const element = shallow(createComponent(onChange));
element
.find("input")
.simulate("change", {target: {value: "Root artifact!"}});
element.find("button").simulate("click");
element
.find("tr textarea")
.simulate("change", {target: {value: "for garlic, carrots, etc."}});
expect(onChange).toHaveBeenLastCalledWith(
new Graph().addNode({
address: artifactAddress(
new Graph(),
"sourcecred",
"artifact-tests",
"Root artifact!"
),
payload: {
name: "Root artifact!",
description: "for garlic, carrots, etc.",
},
})
);
});
it("does not mutate the graph passed to its callback", () => {
const onChange = jest.fn();
const component = (
<ArtifactGraphEditor
settings={{
githubApiToken: "123youdontneedme",
repoOwner: "sourcecred",
repoName: "artifact-tests",
}}
onChange={onChange}
/>
);
const element = shallow(component);
expect(onChange).toHaveBeenCalledTimes(1);
const element = shallow(createComponent(onChange));
const g1 = onChange.mock.calls[0][0];
const g1Copy = g1.copy();
element
.find("input")
.simulate("change", {target: {value: "Root artifact!"}});
element.find("button").simulate("click");
expect(onChange).toHaveBeenCalledTimes(2);
const g2 = onChange.mock.calls[1][0];
expect(g1.equals(new Graph())).toBe(true);
const g2Copy = g2.copy();
expect(g1.equals(g1Copy)).toBe(true);
expect(g1.equals(g2)).toBe(false);
element
.find("tr textarea")
.simulate("change", {target: {value: "for garlic, carrots, etc."}});
expect(onChange).toHaveBeenCalledTimes(3);
const g3 = onChange.mock.calls[2][0];
expect(g1.equals(g1Copy)).toBe(true);
expect(g2.equals(g2Copy)).toBe(true);
expect(g3.equals(g2)).toBe(false);
});
});