From cf7ffc5ddccee351d6860f9668883d2b6a771bb4 Mon Sep 17 00:00:00 2001 From: Alberto Gutierrez Date: Mon, 8 Oct 2018 12:33:10 +0200 Subject: [PATCH] Embed components Signed-off-by: Alberto Gutierrez --- packages/jaeger-ui/src/components/App/Page.js | 9 ++- .../SearchResults/ResultItem.js | 11 +++- .../SearchResults/ResultItemTitle.js | 16 +++-- .../SearchTracePage/SearchResults/index.js | 40 ++++++------ .../SearchResults/index.test.js | 11 ++++ .../src/components/SearchTracePage/index.js | 61 ++++++++++++++----- .../components/SearchTracePage/index.test.js | 22 +++++++ .../src/components/TracePage/index.js | 39 +++++++++--- .../src/components/TracePage/index.test.js | 19 ++++++ 9 files changed, 178 insertions(+), 50 deletions(-) diff --git a/packages/jaeger-ui/src/components/App/Page.js b/packages/jaeger-ui/src/components/App/Page.js index 47fe93fd98..ddc646933b 100644 --- a/packages/jaeger-ui/src/components/App/Page.js +++ b/packages/jaeger-ui/src/components/App/Page.js @@ -52,13 +52,16 @@ export class PageImpl extends React.Component { } render() { + const isEmbed = this.props.search.includes('embed'); return (
-
- -
+ {!isEmbed && ( +
+ +
+ )} {this.props.children}
diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.js index fce348dbe2..fd6c7fddd1 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.js @@ -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'); @@ -44,7 +45,14 @@ export default class ResultItem extends React.PureComponent { 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'); @@ -61,6 +69,7 @@ export default class ResultItem extends React.PureComponent { toggleComparison={toggleComparison} traceID={traceID} traceName={traceName} + disableComparision={disableComparision} /> diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItemTitle.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItemTitle.js index b544eaa9d5..0839c98bc9 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItemTitle.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItemTitle.js @@ -37,6 +37,7 @@ type Props = { toggleComparison: (string, boolean) => void, traceID: string, traceName: string, + disableComparision?: boolean, }; export default class ResultItemTitle extends React.PureComponent { @@ -64,6 +65,7 @@ export default class ResultItemTitle extends React.PureComponent { state, traceID, traceName, + disableComparision, } = this.props; let WrapperComponent = 'div'; const wrapperProps: { [string]: string } = { className: 'ResultItemTitle--item ub-flex-auto' }; @@ -74,12 +76,14 @@ export default class ResultItemTitle extends React.PureComponent { const isErred = state === fetchedState.ERROR; return (
- + {!disableComparision && ( + + )} {duration != null && {formatDuration(duration)}} diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js index bfaa2a670c..d8679c66df 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js @@ -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, @@ -107,26 +110,28 @@ export default class SearchResults extends React.PureComponent ); } - const { goToTrace, maxTraceDuration } = this.props; + const { goToTrace, isEmbed, hideGraph, disableComparision, maxTraceDuration } = this.props; const cohortIds = new Set(diffCohort.map(datum => datum.id)); return (
-
- ({ - x: t.startTime, - y: t.duration, - traceID: t.traceID, - size: t.spans.length, - name: t.traceName, - }))} - onValueClick={t => { - goToTrace(t.traceID); - }} - /> -
+ {!hideGraph && ( +
+ ({ + x: t.startTime, + y: t.duration, + traceID: t.traceID, + size: t.spans.length, + name: t.traceName, + }))} + onValueClick={t => { + goToTrace(t.traceID); + }} + /> +
+ )}

@@ -136,16 +141,17 @@ export default class SearchResults extends React.PureComponent

- {diffSelection} + {!disableComparision && diffSelection}
    {traces.map(trace => (
  • ))} diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.test.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.test.js index df5ad9f588..b70d365df7 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.test.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.test.js @@ -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('', () => { let wrapper; @@ -48,6 +49,16 @@ describe('', () => { 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); diff --git a/packages/jaeger-ui/src/components/SearchTracePage/index.js b/packages/jaeger-ui/src/components/SearchTracePage/index.js index 65cd1b59d8..1d595adb7c 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/index.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/index.js @@ -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'; @@ -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() { @@ -75,6 +83,9 @@ export class SearchTracePageImpl extends Component { maxTraceDuration, services, traceResults, + isEmbed, + hideGraph, + disableComparision, } = this.props; const hasTraceResults = traceResults && traceResults.length > 0; const showErrors = errors && !loadingTraces; @@ -82,13 +93,16 @@ export class SearchTracePageImpl extends Component { return (
    - -
    -

    Find Traces

    - {!loadingServices && services ? : } -
    - + {!isEmbed && ( + +
    +

    Find Traces

    + {!loadingServices && services ? : } +
    + + )} + {isEmbed && } {showErrors && (

    There was an error querying for traces:

    @@ -105,16 +119,20 @@ export class SearchTracePageImpl extends Component { diffCohort={diffCohort} skipMessage={isHomepage} traces={traceResults} + isEmbed={isEmbed} + hideGraph={hideGraph} + disableComparision={disableComparision} /> )} - {showLogo && ( - presentation - )} + {showLogo && + !isEmbed && ( + presentation + )}
    @@ -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, @@ -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); @@ -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, diff --git a/packages/jaeger-ui/src/components/SearchTracePage/index.test.js b/packages/jaeger-ui/src/components/SearchTracePage/index.test.js index b5c4630f10..5733d0f7d6 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/index.test.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/index.test.js @@ -32,6 +32,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'; @@ -48,6 +49,8 @@ describe('', () => { traceResults = [{ traceID: 'a', spans: [], processes: {} }, { traceID: 'b', spans: [], processes: {} }]; props = { traceResults, + isEmbed: false, + disableComparision: false, isHomepage: false, loadingServices: false, loadingTraces: false, @@ -100,6 +103,21 @@ describe('', () => { 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); + }); }); describe('mapStateToProps()', () => { @@ -140,6 +158,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, diff --git a/packages/jaeger-ui/src/components/TracePage/index.js b/packages/jaeger-ui/src/components/TracePage/index.js index a53d1393d0..49d024310c 100644 --- a/packages/jaeger-ui/src/components/TracePage/index.js +++ b/packages/jaeger-ui/src/components/TracePage/index.js @@ -20,9 +20,10 @@ import _mapValues from 'lodash/mapValues'; import _maxBy from 'lodash/maxBy'; import _values from 'lodash/values'; import { connect } from 'react-redux'; +import queryString from 'query-string'; import type { RouterHistory, Match } from 'react-router-dom'; import { bindActionCreators } from 'redux'; -import { Input } from 'antd'; +import { Input, Button } from 'antd'; import ArchiveNotifier from './ArchiveNotifier'; import { actions as archiveActions } from './ArchiveNotifier/duck'; @@ -50,6 +51,7 @@ import type { TraceArchive } from '../../types/archive'; import './index.css'; type TracePageProps = { + query: Object, archiveEnabled: boolean, archiveTraceState: ?TraceArchive, archiveTrace: string => void, @@ -58,6 +60,8 @@ type TracePageProps = { history: RouterHistory, id: string, trace: ?FetchedTrace, + isEmbed?: boolean, + mapCollapsed?: boolean, }; type TracePageState = { @@ -157,6 +161,9 @@ export class TracePageImpl extends React.PureComponent { + filterSpans: string => ?Set = (textFilter: string) => { const spans = this.props.trace && this.props.trace.data && this.props.trace.data.spans; if (!spans) return null; @@ -258,9 +265,7 @@ export class TracePageImpl extends React.PureComponent isTextInKeyValues(log.fields)) || isTextInKeyValues(span.process.tags); - // declare as const because need to disambiguate the type - const rv: Set = new Set(spans.filter(isSpanAMatch).map((span: Span) => span.spanID)); - return rv; + return new Set(spans.filter(isSpanAMatch).map((span: Span) => span.spanID)); }; updateTextFilter = (textFilter: string) => { @@ -326,8 +331,19 @@ export class TracePageImpl extends React.PureComponent { + this.props.history.goBack(); + }; + + goFullView = () => { + const urlQuery = this.props.query; + delete urlQuery.embed; + const url = `/trace/${this.props.id.toLowerCase()}?${queryString.stringify(urlQuery)}`; + window.open(prefixUrl(url), '_blank'); + }; + render() { - const { archiveEnabled, archiveTraceState, trace } = this.props; + const { archiveEnabled, archiveTraceState, trace, isEmbed } = this.props; const { slimView, headerHeight, textFilter, viewRange, findMatchesIDs } = this.state; if (!trace || trace.state === fetchedState.LOADING) { return ; @@ -341,6 +357,12 @@ export class TracePageImpl extends React.PureComponent p.serviceName)).size; return (
    + {isEmbed && ( +
    + + +
    + )} {archiveEnabled && ( )} @@ -397,7 +419,10 @@ export function mapStateToProps(state: ReduxState, ownProps: { match: Match }) { const trace = id ? state.trace.traces[id] : null; const archiveTraceState = id ? state.archive[id] : null; const archiveEnabled = Boolean(state.config.archiveEnabled); - return { archiveEnabled, archiveTraceState, id, trace }; + const query = queryString.parse(state.router.location.search); + const isEmbed = 'embed' in query; + const mapCollapsed = 'mapCollapsed' in query; + return { query, archiveEnabled, archiveTraceState, id, trace, isEmbed, mapCollapsed }; } // export for tests diff --git a/packages/jaeger-ui/src/components/TracePage/index.test.js b/packages/jaeger-ui/src/components/TracePage/index.test.js index 62bfc9c2c1..495c35f7b6 100644 --- a/packages/jaeger-ui/src/components/TracePage/index.test.js +++ b/packages/jaeger-ui/src/components/TracePage/index.test.js @@ -37,6 +37,7 @@ import * as track from './index.track'; import { reset as resetShortcuts } from './keyboard-shortcuts'; import { cancel as cancelScroll } from './scroll-page'; import SpanGraph from './SpanGraph'; +import { Button } from 'antd'; import TracePageHeader from './TracePageHeader'; import { trackSlimHeaderToggle } from './TracePageHeader.track'; import TraceTimelineViewer from './TraceTimelineViewer'; @@ -151,6 +152,16 @@ describe('', () => { expect(cancelScroll.mock.calls).toEqual([[]]); }); + it('collapse map if queryparam mapCollapsed', () => { + wrapper.setProps({ mapCollapsed: true }); + expect(wrapper.find(SpanGraph).length).toBe(0); + }); + + it('show buttons with links to the full site and search if is embed', () => { + wrapper.setProps({ isEmbed: true }); + expect(wrapper.find(Button).length).toBe(2); + }); + describe('_adjustViewRange()', () => { let instance; let time; @@ -359,6 +370,11 @@ describe('mapStateToProps()', () => { [id]: { data: trace, state: fetchedState.DONE }, }, }, + router: { + location: { + search: '', + }, + }, config: { archiveEnabled: false, }, @@ -373,6 +389,9 @@ describe('mapStateToProps()', () => { expect(props).toEqual({ id, archiveEnabled: false, + isEmbed: false, + mapCollapsed: false, + query: {}, archiveTraceState: undefined, trace: { data: {}, state: fetchedState.DONE }, });