Skip to content

Commit 7aaac20

Browse files
authored
Remove ImmutableJS, refactor search selectors (#48)
* Update prettier and wrap at 110 instead of 80 * Remove ImmutableJS from reducers * Remove remaining ImmutableJS-oriented functionality * Refactor search page mapStateToProps * Add flow-types and tests for model/search * Use spread operator instead of Object.assign * Misc inline comments * misc PR feedback Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
1 parent 4137272 commit 7aaac20

25 files changed

+576
-473
lines changed

package.json

-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
"flow-bin": "^0.36.0",
3434
"fuzzy": "^0.1.1",
3535
"global": "^4.3.0",
36-
"immutable": "^3.8.1",
3736
"is-promise": "^2.1.0",
3837
"isomorphic-fetch": "^2.2.1",
3938
"json-markup": "^1.0.0",
@@ -49,7 +48,6 @@
4948
"react-dom": "^15.5.0",
5049
"react-ga": "^2.1.2",
5150
"react-helmet": "^3.1.0",
52-
"react-immutable-proptypes": "^2.1.0",
5351
"react-metrics": "^2.2.3",
5452
"react-redux": "^4.4.5",
5553
"react-router": "^2.7.0",

src/components/DependencyGraph/index.js

+10-13
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ export default class DependencyGraphPage extends Component {
6262
render() {
6363
const { nodes, links, error, dependencies, loading } = this.props;
6464
const { graphType } = this.state;
65-
const serviceCalls = dependencies.toJS();
6665
if (loading) {
6766
return (
6867
<div className="m1">
@@ -86,16 +85,17 @@ export default class DependencyGraphPage extends Component {
8685

8786
const GRAPH_TYPE_OPTIONS = [{ type: 'FORCE_DIRECTED', name: 'Force Directed Graph' }];
8887

89-
if (serviceCalls.length <= 100) {
88+
if (dependencies.length <= 100) {
9089
GRAPH_TYPE_OPTIONS.push({ type: 'DAG', name: 'DAG' });
9190
}
9291
return (
9392
<div className="my2">
9493
<Menu tabular>
9594
{GRAPH_TYPE_OPTIONS.map(option =>
9695
<Menu.Item
97-
name={option.name}
9896
active={graphType === option.type}
97+
key={option.type}
98+
name={option.name}
9999
onClick={() => this.handleGraphTypeChange(option.type)}
100100
/>
101101
)}
@@ -112,7 +112,7 @@ export default class DependencyGraphPage extends Component {
112112
}}
113113
>
114114
{graphType === 'FORCE_DIRECTED' && <DependencyForceGraph nodes={nodes} links={links} />}
115-
{graphType === 'DAG' && <DAG serviceCalls={serviceCalls} />}
115+
{graphType === 'DAG' && <DAG serviceCalls={dependencies} />}
116116
</div>
117117
</div>
118118
);
@@ -121,17 +121,14 @@ export default class DependencyGraphPage extends Component {
121121

122122
// export connected component separately
123123
function mapStateToProps(state) {
124-
const dependencies = state.dependencies.get('dependencies');
125-
let nodes;
124+
const { dependencies, error, loading } = state.dependencies;
126125
let links;
127-
if (dependencies && dependencies.size > 0) {
128-
const nodesAndLinks = formatDependenciesAsNodesAndLinks({ dependencies });
129-
nodes = nodesAndLinks.nodes;
130-
links = nodesAndLinks.links;
126+
let nodes;
127+
if (dependencies && dependencies.length > 0) {
128+
const formatted = formatDependenciesAsNodesAndLinks({ dependencies });
129+
links = formatted.links;
130+
nodes = formatted.nodes;
131131
}
132-
const error = state.dependencies.get('error');
133-
const loading = state.dependencies.get('loading');
134-
135132
return { loading, error, nodes, links, dependencies };
136133
}
137134

src/components/SearchTracePage/TraceSearchForm.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export function TraceSearchFormComponent(props) {
9292
name="service"
9393
component={SearchDropdownInput}
9494
className="ui dropdown"
95-
items={services.concat({ name: '-' }).map(s => ({ text: s.name, value: s.name }))}
95+
items={services.concat({ name: '-' }).map(s => ({ text: s.name, value: s.name, key: s.name }))}
9696
/>
9797
</div>
9898

@@ -102,7 +102,7 @@ export function TraceSearchFormComponent(props) {
102102
name="operation"
103103
component={SearchDropdownInput}
104104
className="ui dropdown"
105-
items={operationsForService.concat('all').map(op => ({ text: op, value: op }))}
105+
items={operationsForService.concat('all').map(op => ({ text: op, value: op, key: op }))}
106106
/>
107107
</div>}
108108

@@ -190,7 +190,12 @@ export function TraceSearchFormComponent(props) {
190190
TraceSearchFormComponent.propTypes = {
191191
handleSubmit: PropTypes.func,
192192
submitting: PropTypes.bool,
193-
services: PropTypes.arrayOf(PropTypes.string),
193+
services: PropTypes.arrayOf(
194+
PropTypes.shape({
195+
name: PropTypes.string,
196+
operations: PropTypes.arrayOf(PropTypes.string),
197+
})
198+
),
194199
selectedService: PropTypes.string,
195200
selectedLookback: PropTypes.string,
196201
};

src/components/SearchTracePage/TraceSearchResult.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ export default function TraceSearchResult({ trace, durationPercent = 100 }) {
5555
<span className="trace-search-result--spans">
5656
{numberOfSpans} span{numberOfSpans > 1 && 's'}
5757
</span>
58-
{numberOfErredSpans &&
58+
{Boolean(numberOfErredSpans) &&
5959
<span className="trace-search-result--erred-spans">
6060
{numberOfErredSpans} error{numberOfErredSpans > 1 && 's'}
6161
</span>}
6262
</div>
6363
<div className="col col-6">
6464
{sortBy(services, s => s.name).map(service =>
6565
<div key={service.name} className="inline-block mr1 mb1">
66-
<TraceServiceTag key={service.name} service={service} />
66+
<TraceServiceTag service={service} />
6767
</div>
6868
)}
6969
</div>

src/components/SearchTracePage/TraceSearchResult.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const testTraceProps = {
2929
services: [
3030
{
3131
name: 'Service A',
32-
numberOfApperancesInTrace: 2,
32+
numberOfSpans: 2,
3333
percentOfTrace: 50,
3434
},
3535
],

src/components/SearchTracePage/TraceServiceTag.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@ import React from 'react';
2323
import colorGenerator from '../../utils/color-generator';
2424

2525
export default function TraceServiceTag({ service }) {
26-
const { name, numberOfApperancesInTrace } = service;
26+
const { name, numberOfSpans } = service;
2727
return (
2828
<div className="ui mini label" style={{ borderLeft: `5px solid ${colorGenerator.getColorByKey(name)}` }}>
29-
{name} ({numberOfApperancesInTrace})
29+
{name} ({numberOfSpans})
3030
</div>
3131
);
3232
}
3333

3434
TraceServiceTag.propTypes = {
3535
service: PropTypes.shape({
3636
name: PropTypes.string.isRequired,
37-
numberOfApperancesInTrace: PropTypes.number.isRequired,
37+
numberOfSpans: PropTypes.number.isRequired,
3838
}).isRequired,
3939
};

src/components/SearchTracePage/TraceServiceTag.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ it('<SearchTracePage /> tests', () => {
2828
<TraceServiceTag
2929
service={{
3030
name: 'Service A',
31-
numberOfApperancesInTrace: 1,
31+
numberOfSpans: 1,
3232
}}
3333
/>
3434
);

src/components/SearchTracePage/index.js

+19-27
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,23 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21+
import _values from 'lodash/values';
2122
import PropTypes from 'prop-types';
2223
import React, { Component } from 'react';
2324
import { bindActionCreators } from 'redux';
2425
import { connect } from 'react-redux';
2526
import { Field, reduxForm, formValueSelector } from 'redux-form';
2627
import { Link } from 'react-router';
2728
import { Sticky } from 'react-sticky';
28-
import * as jaegerApiActions from '../../actions/jaeger-api';
2929

3030
import JaegerLogo from '../../img/jaeger-logo.svg';
3131

32+
import * as jaegerApiActions from '../../actions/jaeger-api';
3233
import TraceSearchForm from './TraceSearchForm';
3334
import TraceSearchResult from './TraceSearchResult';
3435
import TraceResultsScatterPlot from './TraceResultsScatterPlot';
35-
import {
36-
transformTraceResultsSelector,
37-
getSortedTraceResults,
38-
LONGEST_FIRST,
39-
SHORTEST_FIRST,
40-
MOST_SPANS,
41-
LEAST_SPANS,
42-
MOST_RECENT,
43-
} from '../../selectors/search';
36+
import * as orderBy from '../../model/order-by';
37+
import { sortTraces, getTraceSummaries } from '../../model/search';
4438
import { getPercentageOfDuration } from '../../utils/date';
4539
import getLastXformCacher from '../../utils/get-last-xform-cacher';
4640

@@ -52,18 +46,18 @@ let TraceResultsFilterForm = () =>
5246
<div className="field inline">
5347
<label htmlFor="traceResultsSortBy">Sort</label>
5448
<Field name="sortBy" id="traceResultsSortBy" className="ui dropdown" component="select">
55-
<option value={MOST_RECENT}>Most Recent</option>
56-
<option value={LONGEST_FIRST}>Longest First</option>
57-
<option value={SHORTEST_FIRST}>Shortest First</option>
58-
<option value={MOST_SPANS}>Most Spans</option>
59-
<option value={LEAST_SPANS}>Least Spans</option>
49+
<option value={orderBy.MOST_RECENT}>Most Recent</option>
50+
<option value={orderBy.LONGEST_FIRST}>Longest First</option>
51+
<option value={orderBy.SHORTEST_FIRST}>Shortest First</option>
52+
<option value={orderBy.MOST_SPANS}>Most Spans</option>
53+
<option value={orderBy.LEAST_SPANS}>Least Spans</option>
6054
</Field>
6155
</div>
6256
</div>;
6357
TraceResultsFilterForm = reduxForm({
6458
form: 'traceResultsFilters',
6559
initialValues: {
66-
sortBy: MOST_RECENT,
60+
sortBy: orderBy.MOST_RECENT,
6761
},
6862
})(TraceResultsFilterForm);
6963
const traceResultsFiltersFormSelector = formValueSelector('traceResultsFilters');
@@ -194,13 +188,13 @@ SearchTracePage.propTypes = {
194188
};
195189

196190
const stateTraceXformer = getLastXformCacher(stateTrace => {
197-
const { traces: traceMap, loading, error: traceError } = stateTrace.toJS();
198-
const traces = Object.keys(traceMap).map(traceID => traceMap[traceID]);
199-
return { tracesSrc: { traces }, loading, traceError };
191+
const { traces: traceMap, loading, error: traceError } = stateTrace;
192+
const { traces, maxDuration } = getTraceSummaries(_values(traceMap));
193+
return { traces, maxDuration, loading, traceError };
200194
});
201195

202196
const stateServicesXformer = getLastXformCacher(stateServices => {
203-
const { services: serviceList, operationsForService: opsBySvc, error: serviceError } = stateServices.toJS();
197+
const { services: serviceList, operationsForService: opsBySvc, error: serviceError } = stateServices;
204198
const services = serviceList.map(name => ({
205199
name,
206200
operations: opsBySvc[name] || [],
@@ -211,18 +205,17 @@ const stateServicesXformer = getLastXformCacher(stateServices => {
211205
function mapStateToProps(state) {
212206
const query = state.routing.locationBeforeTransitions.query;
213207
const isHomepage = !Object.keys(query).length;
214-
const { tracesSrc, loading, traceError } = stateTraceXformer(state.trace);
215-
const { traces, maxDuration } = transformTraceResultsSelector(tracesSrc);
208+
const { traces, maxDuration, loading, traceError } = stateTraceXformer(state.trace);
216209
const { services, serviceError } = stateServicesXformer(state.services);
217-
const sortBy = traceResultsFiltersFormSelector(state, 'sortBy');
218-
const traceResultsSorted = getSortedTraceResults(traces, sortBy);
219210
const errorMessage = serviceError || traceError ? `${serviceError || ''} ${traceError || ''}` : '';
211+
const sortBy = traceResultsFiltersFormSelector(state, 'sortBy');
212+
sortTraces(traces, sortBy);
220213

221214
return {
222215
isHomepage,
223216
sortTracesBy: sortBy,
224-
traceResults: traceResultsSorted,
225-
numberOfTraceResults: traceResultsSorted.length,
217+
traceResults: traces,
218+
numberOfTraceResults: traces.length,
226219
maxTraceDuration: maxDuration,
227220
urlQueryParams: query,
228221
services,
@@ -233,7 +226,6 @@ function mapStateToProps(state) {
233226

234227
function mapDispatchToProps(dispatch) {
235228
const { searchTraces, fetchServices } = bindActionCreators(jaegerApiActions, dispatch);
236-
237229
return {
238230
searchTraces,
239231
fetchServices,

src/components/TracePage/TraceTimelineViewer/SpanDetail.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function CollapsePanel(props) {
4444
);
4545
}
4646
CollapsePanel.propTypes = {
47-
header: PropTypes.element.isRequired,
47+
header: PropTypes.node.isRequired,
4848
onToggleOpen: PropTypes.func.isRequired,
4949
children: PropTypes.element.isRequired,
5050
open: PropTypes.bool.isRequired,

src/components/TracePage/index.js

+3-8
Original file line numberDiff line numberDiff line change
@@ -168,18 +168,13 @@ export default class TracePage extends Component {
168168

169169
// export connected component separately
170170
function mapStateToProps(state, ownProps) {
171-
const { params: { id } } = ownProps;
172-
173-
let trace = state.trace.getIn(['traces', id]);
171+
const { id } = ownProps.params;
172+
let trace = state.trace.traces[id];
174173
if (trace && !(trace instanceof Error)) {
175-
trace = trace.toJS();
176174
trace = dropEmptyStartTimeSpans(trace);
177175
trace = hydrateSpansWithProcesses(trace);
178176
}
179-
180-
const loading = state.trace.get('loading');
181-
182-
return { id, loading, trace };
177+
return { id, trace, loading: state.trace.loading };
183178
}
184179

185180
function mapDispatchToProps(dispatch) {

src/reducers/index.test.js src/model/order-by.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@
1818
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919
// THE SOFTWARE.
2020

21-
import jaegerReducers from './index';
22-
import traceReducer from './trace';
23-
24-
it('jaegerReducers should contain the trace reducer', () => {
25-
expect(jaegerReducers.trace).toBe(traceReducer);
26-
});
21+
export const MOST_RECENT = 'MOST_RECENT';
22+
export const LONGEST_FIRST = 'LONGEST_FIRST';
23+
export const SHORTEST_FIRST = 'SHORTEST_FIRST';
24+
export const MOST_SPANS = 'MOST_SPANS';
25+
export const LEAST_SPANS = 'LEAST_SPANS';

0 commit comments

Comments
 (0)