Skip to content

Commit

Permalink
Embed components
Browse files Browse the repository at this point in the history
Signed-off-by: Alberto Gutierrez <aljesusg@gmail.com>
  • Loading branch information
aljesusg committed Oct 16, 2018
1 parent feeaccd commit 8f940a9
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 50 deletions.
9 changes: 6 additions & 3 deletions packages/jaeger-ui/src/components/App/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ export class PageImpl extends React.Component<Props> {
}

render() {
const isEmbed = this.props.search.includes('embed');
return (
<div>
<Helmet title="Jaeger UI" />
<Layout>
<Header className="Page--topNav">
<TopNav />
</Header>
{!isEmbed && (
<Header className="Page--topNav">
<TopNav />
</Header>
)}
<Content className="Page--content">{this.props.children}</Content>
</Layout>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Props = {
linkTo: string,
toggleComparison: string => void,
trace: Trace,
disableComparision: boolean,
};

const isErrorTag = ({ key, value }) => key === 'error' && (value === true || value === 'true');
Expand All @@ -44,7 +45,14 @@ export default class ResultItem extends React.PureComponent<Props> {
props: Props;

render() {
const { durationPercent, isInDiffCohort, linkTo, toggleComparison, trace } = this.props;
const {
durationPercent,
isInDiffCohort,
linkTo,
disableComparision,
toggleComparison,
trace,
} = this.props;
const { duration, services, startTime, spans, traceName, traceID } = trace;
const mDate = moment(startTime / 1000);
const timeStr = mDate.format('h:mm:ss a');
Expand All @@ -61,6 +69,7 @@ export default class ResultItem extends React.PureComponent<Props> {
toggleComparison={toggleComparison}
traceID={traceID}
traceName={traceName}
disableComparision={disableComparision}
/>
<Link to={linkTo}>
<Row>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Props = {
toggleComparison: (string, boolean) => void,
traceID: string,
traceName: string,
disableComparision?: boolean,
};

export default class ResultItemTitle extends React.PureComponent<Props> {
Expand Down Expand Up @@ -64,6 +65,7 @@ export default class ResultItemTitle extends React.PureComponent<Props> {
state,
traceID,
traceName,
disableComparision,
} = this.props;
let WrapperComponent = 'div';
const wrapperProps: { [string]: string } = { className: 'ResultItemTitle--item ub-flex-auto' };
Expand All @@ -74,12 +76,14 @@ export default class ResultItemTitle extends React.PureComponent<Props> {
const isErred = state === fetchedState.ERROR;
return (
<div className="ResultItemTitle">
<Checkbox
className="ResultItemTitle--item ub-flex-none"
checked={!isErred && isInDiffCohort}
disabled={isErred}
onChange={this.toggleComparison}
/>
{!disableComparision && (
<Checkbox
className="ResultItemTitle--item ub-flex-none"
checked={!isErred && isInDiffCohort}
disabled={isErred}
onChange={this.toggleComparison}
/>
)}
<WrapperComponent {...wrapperProps}>
<span className="ResultItemTitle--durationBar" style={{ width: `${durationPercent}%` }} />
{duration != null && <span className="ub-right ub-relative">{formatDuration(duration)}</span>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type SearchResultsProps = {
cohortRemoveTrace: string => void,
diffCohort: FetchedTrace[],
goToTrace: string => void,
isEmbed?: boolean,
hideGraph?: boolean,
disableComparision?: boolean,
loading: boolean,
maxTraceDuration: number,
skipMessage?: boolean,
Expand Down Expand Up @@ -107,26 +110,28 @@ export default class SearchResults extends React.PureComponent<SearchResultsProp
</React.Fragment>
);
}
const { goToTrace, maxTraceDuration } = this.props;
const { goToTrace, isEmbed, hideGraph, disableComparision, maxTraceDuration } = this.props;
const cohortIds = new Set(diffCohort.map(datum => datum.id));
return (
<div>
<div>
<div className="SearchResults--header">
<div className="ub-p3">
<ScatterPlot
data={traces.map(t => ({
x: t.startTime,
y: t.duration,
traceID: t.traceID,
size: t.spans.length,
name: t.traceName,
}))}
onValueClick={t => {
goToTrace(t.traceID);
}}
/>
</div>
{!hideGraph && (
<div className="ub-p3">
<ScatterPlot
data={traces.map(t => ({
x: t.startTime,
y: t.duration,
traceID: t.traceID,
size: t.spans.length,
name: t.traceName,
}))}
onValueClick={t => {
goToTrace(t.traceID);
}}
/>
</div>
)}
<div className="SearchResults--headerOverview">
<SelectSort />
<h2 className="ub-m0">
Expand All @@ -136,16 +141,17 @@ export default class SearchResults extends React.PureComponent<SearchResultsProp
</div>
</div>
<div>
{diffSelection}
{!disableComparision && diffSelection}
<ul className="ub-list-reset">
{traces.map(trace => (
<li className="ub-my3" key={trace.traceID}>
<ResultItem
durationPercent={getPercentageOfDuration(trace.duration, maxTraceDuration)}
isInDiffCohort={cohortIds.has(trace.traceID)}
linkTo={prefixUrl(`/trace/${trace.traceID}`)}
linkTo={prefixUrl(isEmbed ? `/trace/${trace.traceID}?embed` : `/trace/${trace.traceID}`)}
toggleComparison={this.toggleComparison}
trace={trace}
disableComparision={disableComparision}
/>
</li>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as markers from './index.markers';
import ResultItem from './ResultItem';
import ScatterPlot from './ScatterPlot';
import LoadingIndicator from '../../common/LoadingIndicator';
import DiffSelection from './DiffSelection';

describe('<SearchResults>', () => {
let wrapper;
Expand Down Expand Up @@ -48,6 +49,16 @@ describe('<SearchResults>', () => {
expect(wrapper.find(LoadingIndicator).length).toBe(1);
});

it('hide scatter plot if queryparam hideGraph', () => {
wrapper.setProps({ hideGraph: true });
expect(wrapper.find(ScatterPlot).length).toBe(0);
});

it('hide DiffSelection if queryparam disableComparision', () => {
wrapper.setProps({ disableComparision: true });
expect(wrapper.find(DiffSelection).length).toBe(0);
});

describe('search finished with results', () => {
it('shows a scatter plot', () => {
expect(wrapper.find(ScatterPlot).length).toBe(1);
Expand Down
61 changes: 45 additions & 16 deletions packages/jaeger-ui/src/components/SearchTracePage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import React, { Component } from 'react';
import { Col, Row } from 'antd';
import { Col, Row, Button } from 'antd';
import PropTypes from 'prop-types';
import queryString from 'query-string';
import { connect } from 'react-redux';
Expand Down Expand Up @@ -60,7 +60,15 @@ export class SearchTracePageImpl extends Component {
}

goToTrace = traceID => {
this.props.history.push(prefixUrl(`/trace/${traceID}`));
const url = this.props.isEmbed ? `/trace/${traceID}?embed` : `/trace/${traceID}`;
this.props.history.push(prefixUrl(url));
};

goFullView = () => {
const urlQuery = this.props.query;
delete urlQuery.embed;
const url = `/search?${queryString.stringify(urlQuery)}`;
window.open(prefixUrl(url), '_blank');
};

render() {
Expand All @@ -75,20 +83,26 @@ export class SearchTracePageImpl extends Component {
maxTraceDuration,
services,
traceResults,
isEmbed,
hideGraph,
disableComparision,
} = this.props;
const hasTraceResults = traceResults && traceResults.length > 0;
const showErrors = errors && !loadingTraces;
const showLogo = isHomepage && !hasTraceResults && !loadingTraces && !errors;
return (
<div>
<Row>
<Col span={6} className="SearchTracePage--column">
<div className="SearchTracePage--find">
<h2>Find Traces</h2>
{!loadingServices && services ? <SearchForm services={services} /> : <LoadingIndicator />}
</div>
</Col>
{!isEmbed && (
<Col span={6} className="SearchTracePage--column">
<div className="SearchTracePage--find">
<h2>Find Traces</h2>
{!loadingServices && services ? <SearchForm services={services} /> : <LoadingIndicator />}
</div>
</Col>
)}
<Col span={18} className="SearchTracePage--column">
{isEmbed && <Button onClick={this.goFullView}>Show full view</Button>}
{showErrors && (
<div className="js-test-error-message">
<h2>There was an error querying for traces:</h2>
Expand All @@ -105,16 +119,20 @@ export class SearchTracePageImpl extends Component {
diffCohort={diffCohort}
skipMessage={isHomepage}
traces={traceResults}
isEmbed={isEmbed}
hideGraph={hideGraph}
disableComparision={disableComparision}
/>
)}
{showLogo && (
<img
className="SearchTracePage--logo js-test-logo"
alt="presentation"
src={JaegerLogo}
width="400"
/>
)}
{showLogo &&
!isEmbed && (
<img
className="SearchTracePage--logo js-test-logo"
alt="presentation"
src={JaegerLogo}
width="400"
/>
)}
</Col>
</Row>
</div>
Expand All @@ -123,7 +141,11 @@ export class SearchTracePageImpl extends Component {
}

SearchTracePageImpl.propTypes = {
query: PropTypes.object,
isHomepage: PropTypes.bool,
isEmbed: PropTypes.bool,
hideGraph: PropTypes.bool,
disableComparision: PropTypes.bool,
// eslint-disable-next-line react/forbid-prop-types
traceResults: PropTypes.array,
diffCohort: PropTypes.array,
Expand Down Expand Up @@ -196,6 +218,9 @@ const stateServicesXformer = getLastXformCacher(stateServices => {
// export to test
export function mapStateToProps(state) {
const query = queryString.parse(state.router.location.search);
const isEmbed = 'embed' in query;
const hideGraph = 'hideGraph' in query;
const disableComparision = 'disableComparision' in query;
const isHomepage = !Object.keys(query).length;
const { traces, maxDuration, traceError, loadingTraces } = stateTraceXformer(state.trace);
const diffCohort = stateTraceDiffXformer(state.trace, state.traceDiff);
Expand All @@ -210,7 +235,11 @@ export function mapStateToProps(state) {
const sortBy = sortFormSelector(state, 'sortBy');
const traceResults = sortedTracesXformer(traces, sortBy);
return {
query,
diffCohort,
isEmbed,
hideGraph,
disableComparision,
isHomepage,
loadingServices,
loadingTraces,
Expand Down
31 changes: 31 additions & 0 deletions packages/jaeger-ui/src/components/SearchTracePage/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import prefixUrl from '../../utils/prefix-url';

jest.mock('redux-form', () => {
function reduxForm() {
return component => component;
Expand All @@ -32,6 +34,7 @@ import { shallow, mount } from 'enzyme';
import store from 'store';

import { SearchTracePageImpl as SearchTracePage, mapStateToProps } from './index';
import { Button } from 'antd';
import SearchForm from './SearchForm';
import LoadingIndicator from '../common/LoadingIndicator';
import { fetchedState } from '../../constants';
Expand All @@ -48,6 +51,8 @@ describe('<SearchTracePage>', () => {
traceResults = [{ traceID: 'a', spans: [], processes: {} }, { traceID: 'b', spans: [], processes: {} }];
props = {
traceResults,
isEmbed: false,
disableComparision: false,
isHomepage: false,
loadingServices: false,
loadingTraces: false,
Expand Down Expand Up @@ -100,6 +105,28 @@ describe('<SearchTracePage>', () => {
wrapper.setProps({ isHomepage: true, traceResults: [] });
expect(wrapper.find('.js-test-logo').length).toBe(1);
});

it('shows button with a link to the Search page if is embed', () => {
wrapper.setProps({ isEmbed: true });
expect(wrapper.find(Button).length).toBe(1);
});

it('hide SearchForm if is embed', () => {
wrapper.setProps({ isEmbed: true });
expect(wrapper.find(SearchForm).length).toBe(0);
});

it('hide logo if is embed', () => {
wrapper.setProps({ isEmbed: true });
expect(wrapper.find('.js-test-logo').length).toBe(0);
});

it('open a window when goFullView is called', () => {
wrapper.setProps({ query: { embed: 'embed', service: 'jaeger-query' } });
global.open = jest.fn();
wrapper.instance().goFullView();
expect(global.open).toBeCalledWith(prefixUrl('/search?service=jaeger-query'), '_blank');
});
});

describe('mapStateToProps()', () => {
Expand Down Expand Up @@ -140,6 +167,10 @@ describe('mapStateToProps()', () => {
expect(diffCohort[0].data.traceID).toBe(trace.traceID);

expect(rest).toEqual({
isEmbed: false,
hideGraph: false,
disableComparision: false,
query: {},
isHomepage: true,
// the redux-form `formValueSelector` mock returns `null` for "sortBy"
sortTracesBy: null,
Expand Down
Loading

0 comments on commit 8f940a9

Please sign in to comment.