diff --git a/src/components/SearchTracePage/SearchResults/ResultItem.js b/src/components/SearchTracePage/SearchResults/ResultItem.js index 9dceaf0cfe..d46c6af744 100644 --- a/src/components/SearchTracePage/SearchResults/ResultItem.js +++ b/src/components/SearchTracePage/SearchResults/ResultItem.js @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React from 'react'; +import * as React from 'react'; import { Col, Divider, Row, Tag } from 'antd'; import { sortBy } from 'lodash'; import moment from 'moment'; @@ -28,60 +28,64 @@ import type { TraceSummary } from '../../../types/search'; import './ResultItem.css'; -export default function ResultItem({ - trace, - durationPercent = 100, -}: { +type Props = { trace: TraceSummary, durationPercent: number, -}) { - const { duration, services, timestamp, numberOfErredSpans, numberOfSpans, traceName } = trace; - const mDate = moment(timestamp); - const timeStr = mDate.format('h:mm:ss a'); - const fromNow = mDate.fromNow(); - return ( -
-
- - {formatDuration(duration * 1000)} -

{traceName || FALLBACK_TRACE_NAME}

-
- - - - {numberOfSpans} Span{numberOfSpans > 1 && 's'} - - {Boolean(numberOfErredSpans) && ( - - {numberOfErredSpans} Error{numberOfErredSpans > 1 && 's'} +}; + +export default class ResultItem extends React.PureComponent { + props: Props; + + render() { + const { durationPercent, trace } = this.props; + const { duration, services, timestamp, numberOfErredSpans, numberOfSpans, traceName } = trace; + const mDate = moment(timestamp); + const timeStr = mDate.format('h:mm:ss a'); + const fromNow = mDate.fromNow(); + return ( +
+
+ + {formatDuration(duration * 1000)} +

{traceName || FALLBACK_TRACE_NAME}

+
+ + + + {numberOfSpans} Span{numberOfSpans > 1 && 's'} - )} - - -
    - {sortBy(services, s => s.name).map(service => { - const { name, numberOfSpans: count } = service; - return ( -
  • - - {name} ({count}) - -
  • - ); - })} -
- - - {formatRelativeDate(timestamp)} - - {timeStr.slice(0, -3)} {timeStr.slice(-2)} -
- {fromNow} - -
-
- ); + {Boolean(numberOfErredSpans) && ( + + {numberOfErredSpans} Error{numberOfErredSpans > 1 && 's'} + + )} + + +
    + {sortBy(services, s => s.name).map(service => { + const { name, numberOfSpans: count } = service; + return ( +
  • + + {name} ({count}) + +
  • + ); + })} +
+ + + {formatRelativeDate(timestamp)} + + {timeStr.slice(0, -3)} {timeStr.slice(-2)} +
+ {fromNow} + +
+
+ ); + } } diff --git a/src/components/SearchTracePage/SearchResults/index.js b/src/components/SearchTracePage/SearchResults/index.js index 4f7bc0da10..26d7fd0b5f 100644 --- a/src/components/SearchTracePage/SearchResults/index.js +++ b/src/components/SearchTracePage/SearchResults/index.js @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React from 'react'; +import * as React from 'react'; import { Select } from 'antd'; import { Field, reduxForm, formValueSelector } from 'redux-form'; import { Link } from 'react-router-dom'; @@ -66,58 +66,62 @@ const SelectSort = reduxForm({ export const sortFormSelector = formValueSelector('traceResultsSort'); -export default function SearchResults(props: SearchResultsProps) { - const { goToTrace, loading, maxTraceDuration, traces } = props; - if (loading) { - return ; - } - if (!Array.isArray(traces) || !traces.length) { +export default class SearchResults extends React.PureComponent { + props: SearchResultsProps; + + render() { + const { goToTrace, loading, maxTraceDuration, traces } = this.props; + if (loading) { + return ; + } + if (!Array.isArray(traces) || !traces.length) { + return ( +
+ No trace results. Try another query. +
+ ); + } return ( -
- No trace results. Try another query. -
- ); - } - return ( -
-
-
- ({ - x: t.timestamp, - y: t.duration, - traceID: t.traceID, - size: t.numberOfSpans, - name: t.traceName, - }))} - onValueClick={t => { - goToTrace(t.traceID); - }} - /> -
-
- -

- {traces.length} Trace{traces.length > 1 && 's'} -

+
+
+
+ ({ + x: t.timestamp, + y: t.duration, + traceID: t.traceID, + size: t.numberOfSpans, + name: t.traceName, + }))} + onValueClick={t => { + goToTrace(t.traceID); + }} + /> +
+
+ +

+ {traces.length} Trace{traces.length > 1 && 's'} +

+
+
+
    + {traces.map(trace => ( +
  • + + + +
  • + ))} +
+
-
-
    - {traces.map(trace => ( -
  • - - - -
  • - ))} -
-
-
- ); + ); + } } diff --git a/src/components/SearchTracePage/index.js b/src/components/SearchTracePage/index.js index 8e3f52a65c..c832f0590b 100644 --- a/src/components/SearchTracePage/index.js +++ b/src/components/SearchTracePage/index.js @@ -139,6 +139,12 @@ const stateTraceXformer = getLastXformCacher(stateTrace => { return { traces, maxDuration, traceError, loadingTraces }; }); +const sortedTracesXformer = getLastXformCacher((traces, sortBy) => { + const traceResults = traces.slice(); + sortTraces(traceResults, sortBy); + return traceResults; +}); + const stateServicesXformer = getLastXformCacher(stateServices => { const { loading: loadingServices, @@ -169,17 +175,16 @@ export function mapStateToProps(state) { errors.push(serviceError); } const sortBy = sortFormSelector(state, 'sortBy'); - sortTraces(traces, sortBy); - + const traceResults = sortedTracesXformer(traces, sortBy); return { isHomepage, services, + traceResults, loadingTraces, loadingServices, errors: errors.length ? errors : null, maxTraceDuration: maxDuration, sortTracesBy: sortBy, - traceResults: traces, urlQueryParams: query, }; } diff --git a/src/index.js b/src/index.js index 6657e48778..004ee47082 100644 --- a/src/index.js +++ b/src/index.js @@ -21,8 +21,10 @@ import { document } from 'global'; import JaegerUIApp from './components/App'; import { init as initTracking } from './utils/metrics'; +import 'u-basscss/css/flexbox.css'; import 'u-basscss/css/layout.css'; import 'u-basscss/css/margin.css'; +import 'u-basscss/css/padding.css'; import 'u-basscss/css/position.css'; import 'u-basscss/css/typography.css';