Skip to content

Commit ae44538

Browse files
authored
Merge pull request #52 from smacker/code_uast_buttons
Add code and UAST buttons in results table
2 parents d3e8ef0 + 6b92c1b commit ae44538

File tree

7 files changed

+731
-7
lines changed

7 files changed

+731
-7
lines changed

frontend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"prettier": "^1.12.1",
3434
"react-app-rewire-less": "^2.1.1",
3535
"react-app-rewired": "^1.5.2",
36-
"whatwg-url": "^6.4.1"
36+
"whatwg-url": "^6.4.1",
37+
"react-test-renderer": "^16.4.0"
3738
},
3839
"proxy": {
3940
"/query": {

frontend/src/App.js

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { Component } from 'react';
22
import { Helmet } from 'react-helmet';
3-
import { Grid, Row, Col } from 'react-bootstrap';
3+
import { Grid, Row, Col, Modal } from 'react-bootstrap';
44
import SplitPane from 'react-split-pane';
55
import Sidebar from './components/Sidebar';
66
import QueryBox from './components/QueryBox';
@@ -20,14 +20,23 @@ class App extends Component {
2020
) as t
2121
GROUP BY committer_email, month, repo_id`,
2222
results: new Map(),
23-
schema: undefined
23+
schema: undefined,
24+
25+
// modal
26+
showModal: false,
27+
modalTitle: null,
28+
modalContent: null
2429
};
2530

2631
this.handleTextChange = this.handleTextChange.bind(this);
2732
this.handleSubmit = this.handleSubmit.bind(this);
2833
this.handleRemoveResult = this.handleRemoveResult.bind(this);
2934
this.handleTableClick = this.handleTableClick.bind(this);
3035
this.handleExampleClick = this.handleExampleClick.bind(this);
36+
this.handleModalClose = this.handleModalClose.bind(this);
37+
38+
this.showCode = this.showCode.bind(this);
39+
this.showUAST = this.showUAST.bind(this);
3140

3241
this.uniqueKey = 0;
3342
}
@@ -97,6 +106,26 @@ GROUP BY committer_email, month, repo_id`,
97106
});
98107
}
99108

109+
handleModalClose() {
110+
this.setState({ showModal: false, modalTitle: null, modalContent: null });
111+
}
112+
113+
showCode(code) {
114+
this.setState({
115+
showModal: true,
116+
modalTitle: 'Source code',
117+
modalContent: <pre>{code}</pre>
118+
});
119+
}
120+
121+
showUAST(uast) {
122+
this.setState({
123+
showModal: true,
124+
modalTitle: 'UAST',
125+
modalContent: <pre>{JSON.stringify(uast, null, 2)}</pre>
126+
});
127+
}
128+
100129
componentDidMount() {
101130
this.loadSchema();
102131
}
@@ -119,6 +148,8 @@ GROUP BY committer_email, month, repo_id`,
119148
results={results}
120149
handleRemoveResult={this.handleRemoveResult}
121150
handleEditQuery={this.handleTextChange}
151+
showCode={this.showCode}
152+
showUAST={this.showUAST}
122153
/>
123154
</Col>
124155
);
@@ -159,6 +190,16 @@ GROUP BY committer_email, month, repo_id`,
159190
</Col>
160191
</Row>
161192
</Grid>
193+
<Modal
194+
show={this.state.showModal}
195+
onHide={this.handleModalClose}
196+
bsSize="large"
197+
>
198+
<Modal.Header closeButton>
199+
<Modal.Title>{this.state.modalTitle}</Modal.Title>
200+
</Modal.Header>
201+
<Modal.Body>{this.state.modalContent}</Modal.Body>
202+
</Modal>
162203
</div>
163204
);
164205
}

frontend/src/components/ResultsTable.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import React, { Component } from 'react';
22
import PropTypes from 'prop-types';
33
import ReactTable from 'react-table';
4+
import { Button } from 'react-bootstrap';
45
import 'react-table/react-table.css';
56
import './ResultsTable.less';
67

78
class ResultsTable extends Component {
89
render() {
10+
const { showCode, showUAST } = this.props;
911
const columns = this.props.response.meta.headers.map(col => ({
1012
Header: col,
1113
id: col,
@@ -14,8 +16,15 @@ class ResultsTable extends Component {
1416
switch (typeof v) {
1517
case 'boolean':
1618
return v.toString();
19+
case 'string':
20+
// assume any multiline string is code
21+
if (v.indexOf('\n') > -1) {
22+
return <Button onClick={() => showCode(v)}>Code</Button>;
23+
}
24+
return v;
1725
case 'object':
18-
return JSON.stringify(v, null, 2);
26+
// UAST column
27+
return <Button onClick={() => showUAST(v)}>UAST</Button>;
1928
default:
2029
return v;
2130
}
@@ -35,7 +44,9 @@ class ResultsTable extends Component {
3544

3645
ResultsTable.propTypes = {
3746
// Must be a success response
38-
response: PropTypes.object.isRequired
47+
response: PropTypes.object.isRequired,
48+
showCode: PropTypes.func.isRequired,
49+
showUAST: PropTypes.func.isRequired
3950
};
4051

4152
export default ResultsTable;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from 'react';
2+
import renderer from 'react-test-renderer';
3+
import ResultsTable from './ResultsTable';
4+
5+
describe('ResultsTable', () => {
6+
const noop = () => null;
7+
8+
it('text with new lines should be shown as code', () => {
9+
const response = {
10+
meta: {
11+
headers: ['notCode', 'code'],
12+
types: ['TEXT', 'TEXT']
13+
},
14+
data: [{ notCode: 'not a code', code: 'this\nis\ncode' }]
15+
};
16+
const tree = renderer
17+
.create(
18+
<ResultsTable response={response} showCode={noop} showUAST={noop} />
19+
)
20+
.toJSON();
21+
22+
expect(tree).toMatchSnapshot();
23+
});
24+
});

frontend/src/components/TabbedResults.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class TabbedResults extends Component {
4343
}
4444

4545
render() {
46+
const { showCode, showUAST } = this.props;
47+
4648
return (
4749
<Tabs
4850
id="tabbed-results"
@@ -85,7 +87,13 @@ class TabbedResults extends Component {
8587
</Row>
8688
);
8789
} else {
88-
content = <ResultsTable response={query.response} />;
90+
content = (
91+
<ResultsTable
92+
response={query.response}
93+
showCode={showCode}
94+
showUAST={showUAST}
95+
/>
96+
);
8997
}
9098

9199
return (
@@ -121,7 +129,9 @@ TabbedResults.propTypes = {
121129
// response: object Required if loading and errorMsg are not present
122130
results: PropTypes.instanceOf(Map).isRequired,
123131
handleRemoveResult: PropTypes.func.isRequired,
124-
handleEditQuery: PropTypes.func.isRequired
132+
handleEditQuery: PropTypes.func.isRequired,
133+
showCode: PropTypes.func.isRequired,
134+
showUAST: PropTypes.func.isRequired
125135
};
126136

127137
export default TabbedResults;

0 commit comments

Comments
 (0)