From 8f1bf1de9e6c5b26eb0f907c1082536b63c5922e Mon Sep 17 00:00:00 2001 From: Alberto Gutierrez Date: Mon, 8 Oct 2018 12:33:10 +0200 Subject: [PATCH] SearchTrace and TracePage Embedded components Signed-off-by: Alberto Gutierrez --- packages/jaeger-ui/src/components/App/Page.js | 12 +- .../jaeger-ui/src/components/App/Page.test.js | 19 ++ .../SearchResults/ResultItem.js | 11 +- .../SearchResults/ResultItemTitle.js | 16 +- .../SearchTracePage/SearchResults/index.js | 74 ++++++-- .../SearchResults/index.test.js | 11 ++ .../src/components/SearchTracePage/index.js | 55 ++++-- .../components/SearchTracePage/index.test.js | 14 ++ .../components/TracePage/TracePageHeader.css | 10 +- .../components/TracePage/TracePageHeader.js | 1 + .../TracePage/TracePageHeaderEmbed.js | 178 ++++++++++++++++++ .../TracePage/TracePageHeaderEmbed.test.js | 61 ++++++ .../src/components/TracePage/index.js | 90 ++++++--- .../src/components/TracePage/index.test.js | 65 +++++++ .../jaeger-ui/src/utils/embedded/index.js | 25 +++ .../src/utils/embedded/index.test.js | 32 ++++ 16 files changed, 603 insertions(+), 71 deletions(-) create mode 100644 packages/jaeger-ui/src/components/TracePage/TracePageHeaderEmbed.js create mode 100644 packages/jaeger-ui/src/components/TracePage/TracePageHeaderEmbed.test.js create mode 100644 packages/jaeger-ui/src/utils/embedded/index.js create mode 100644 packages/jaeger-ui/src/utils/embedded/index.test.js diff --git a/packages/jaeger-ui/src/components/App/Page.js b/packages/jaeger-ui/src/components/App/Page.js index 47fe93fd98..fe18c06f6a 100644 --- a/packages/jaeger-ui/src/components/App/Page.js +++ b/packages/jaeger-ui/src/components/App/Page.js @@ -20,7 +20,7 @@ import Helmet from 'react-helmet'; import { connect } from 'react-redux'; import type { Location } from 'react-router-dom'; import { withRouter } from 'react-router-dom'; - +import { isEmbed } from '../../utils/embedded'; import TopNav from './TopNav'; import { trackPageView } from '../../utils/tracking'; @@ -56,10 +56,12 @@ export class PageImpl extends React.Component {
-
- -
- {this.props.children} + {!isEmbed(this.props.search) && ( +
+ +
+ )} + {this.props.children}
); diff --git a/packages/jaeger-ui/src/components/App/Page.test.js b/packages/jaeger-ui/src/components/App/Page.test.js index c8e5fef3b3..8fa4e5d4d0 100644 --- a/packages/jaeger-ui/src/components/App/Page.test.js +++ b/packages/jaeger-ui/src/components/App/Page.test.js @@ -61,4 +61,23 @@ describe('', () => { wrapper.setProps(props); expect(trackPageView.mock.calls).toEqual([[props.pathname, props.search]]); }); + + describe('Page embedded', () => { + beforeEach(() => { + trackPageView.mockReset(); + props = { + pathname: String(Math.random()), + search: 'embed=v0&hideGraph', + }; + wrapper = mount(); + }); + + it('does not explode', () => { + expect(wrapper).toBeDefined(); + }); + + it('does not render Header', () => { + expect(wrapper.find('Header').length).toBe(0); + }); + }); }); diff --git a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.js b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/ResultItem.js index fce348dbe2..b72d93d7da 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 { + disableComparision, + durationPercent, + isInDiffCohort, + linkTo, + 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..d6a25b792f 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.js @@ -15,7 +15,7 @@ // limitations under the License. import * as React from 'react'; -import { Select } from 'antd'; +import { Select, Button } from 'antd'; import { Field, reduxForm, formValueSelector } from 'redux-form'; import DiffSelection from './DiffSelection'; @@ -27,6 +27,7 @@ import * as orderBy from '../../../model/order-by'; import { getPercentageOfDuration } from '../../../utils/date'; import prefixUrl from '../../../utils/prefix-url'; import reduxFormFieldAdapter from '../../../utils/redux-form-field-adapter'; +import { VERSION_API } from '../../../utils/embedded'; import type { FetchedTrace } from '../../../types'; @@ -37,7 +38,10 @@ type SearchResultsProps = { cohortRemoveTrace: string => void, diffCohort: FetchedTrace[], goToTrace: string => void, + embed?: boolean, + hideGraph?: boolean, loading: boolean, + getSearchURL: () => string, maxTraceDuration: number, skipMessage?: boolean, traces: TraceSummary[], @@ -85,8 +89,20 @@ export default class SearchResults extends React.PureComponent; + const { + loading, + diffCohort, + skipMessage, + traces, + goToTrace, + embed, + hideGraph, + getSearchURL, + maxTraceDuration, + } = this.props; + const diffSelection = !embed && ( + + ); if (loading) { return ( @@ -107,28 +123,41 @@ export default class SearchResults extends React.PureComponent ); } - const { goToTrace, 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); + }} + /> +
+ )}
+ {embed && ( + + )}

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

@@ -143,9 +172,16 @@ export default class SearchResults extends React.PureComponent ))} 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..58dfb9321f 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.test.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/SearchResults/index.test.js @@ -19,6 +19,7 @@ import SearchResults from './'; import * as markers from './index.markers'; import ResultItem from './ResultItem'; import ScatterPlot from './ScatterPlot'; +import DiffSelection from './DiffSelection.js'; import LoadingIndicator from '../../common/LoadingIndicator'; describe('', () => { @@ -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 is an embedded component', () => { + wrapper.setProps({ embed: true, getSearchURL: () => 'SEARCH_URL' }); + 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..fb84ebaa71 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/index.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/index.js @@ -30,6 +30,7 @@ import { fetchedState } from '../../constants'; import { sortTraces } from '../../model/search'; import getLastXformCacher from '../../utils/get-last-xform-cacher'; import prefixUrl from '../../utils/prefix-url'; +import { isEmbed } from '../../utils/embedded'; import './index.css'; import JaegerLogo from '../../img/jaeger-logo.svg'; @@ -60,7 +61,14 @@ export class SearchTracePageImpl extends Component { } goToTrace = traceID => { - this.props.history.push(prefixUrl(`/trace/${traceID}`)); + const url = this.props.embed ? `/trace/${traceID}?embed` : `/trace/${traceID}`; + this.props.history.push(prefixUrl(url)); + }; + + getSearchURL = () => { + const urlQuery = this.props.query; + delete urlQuery.embed; + return `/search?${queryString.stringify(urlQuery)}`; }; render() { @@ -75,6 +83,8 @@ export class SearchTracePageImpl extends Component { maxTraceDuration, services, traceResults, + embed, + hideGraph, } = this.props; const hasTraceResults = traceResults && traceResults.length > 0; const showErrors = errors && !loadingTraces; @@ -82,13 +92,15 @@ export class SearchTracePageImpl extends Component { return (
- -
-

Find Traces

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

Find Traces

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

There was an error querying for traces:

@@ -104,17 +116,21 @@ export class SearchTracePageImpl extends Component { cohortRemoveTrace={cohortRemoveTrace} diffCohort={diffCohort} skipMessage={isHomepage} + getSearchURL={this.getSearchURL} traces={traceResults} + embed={embed} + hideGraph={hideGraph} /> )} - {showLogo && ( - presentation - )} + {showLogo && + !embed && ( + presentation + )}
@@ -123,7 +139,10 @@ export class SearchTracePageImpl extends Component { } SearchTracePageImpl.propTypes = { + query: PropTypes.object, isHomepage: PropTypes.bool, + embed: PropTypes.bool, + hideGraph: PropTypes.bool, // eslint-disable-next-line react/forbid-prop-types traceResults: PropTypes.array, diffCohort: PropTypes.array, @@ -196,6 +215,7 @@ const stateServicesXformer = getLastXformCacher(stateServices => { // export to test export function mapStateToProps(state) { const query = queryString.parse(state.router.location.search); + const { hideGraph } = queryString.parse(state.router.location.search); const isHomepage = !Object.keys(query).length; const { traces, maxDuration, traceError, loadingTraces } = stateTraceXformer(state.trace); const diffCohort = stateTraceDiffXformer(state.trace, state.traceDiff); @@ -210,7 +230,10 @@ export function mapStateToProps(state) { const sortBy = sortFormSelector(state, 'sortBy'); const traceResults = sortedTracesXformer(traces, sortBy); return { + query, diffCohort, + embed: isEmbed(state.router.location.search), + hideGraph: hideGraph !== undefined, 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..7a86061ef3 100644 --- a/packages/jaeger-ui/src/components/SearchTracePage/index.test.js +++ b/packages/jaeger-ui/src/components/SearchTracePage/index.test.js @@ -48,6 +48,7 @@ describe('', () => { traceResults = [{ traceID: 'a', spans: [], processes: {} }, { traceID: 'b', spans: [], processes: {} }]; props = { traceResults, + embed: false, isHomepage: false, loadingServices: false, loadingTraces: false, @@ -100,6 +101,16 @@ describe('', () => { wrapper.setProps({ isHomepage: true, traceResults: [] }); expect(wrapper.find('.js-test-logo').length).toBe(1); }); + + it('hide SearchForm if is embed', () => { + wrapper.setProps({ embed: true }); + expect(wrapper.find(SearchForm).length).toBe(0); + }); + + it('hide logo if is embed', () => { + wrapper.setProps({ embed: true }); + expect(wrapper.find('.js-test-logo').length).toBe(0); + }); }); describe('mapStateToProps()', () => { @@ -140,6 +151,9 @@ describe('mapStateToProps()', () => { expect(diffCohort[0].data.traceID).toBe(trace.traceID); expect(rest).toEqual({ + embed: false, + hideGraph: false, + query: {}, isHomepage: true, // the redux-form `formValueSelector` mock returns `null` for "sortBy" sortTracesBy: null, diff --git a/packages/jaeger-ui/src/components/TracePage/TracePageHeader.css b/packages/jaeger-ui/src/components/TracePage/TracePageHeader.css index 11ba9965de..ec5db972bb 100644 --- a/packages/jaeger-ui/src/components/TracePage/TracePageHeader.css +++ b/packages/jaeger-ui/src/components/TracePage/TracePageHeader.css @@ -19,7 +19,15 @@ limitations under the License. display: flex; } -.TracePageHeader--title { +.TracePageHeader--titleRowEmbed { + align-items: center; + background-color: #ececec; + border-bottom: 1px solid #d8d8d8; + display: flex; +} + +.TracePageHeader--title, +.TracePageHeader--titleEmbed { margin: 0; padding: 0.25rem 0.5rem; } diff --git a/packages/jaeger-ui/src/components/TracePage/TracePageHeader.js b/packages/jaeger-ui/src/components/TracePage/TracePageHeader.js index f308d852f0..8689264b7c 100644 --- a/packages/jaeger-ui/src/components/TracePage/TracePageHeader.js +++ b/packages/jaeger-ui/src/components/TracePage/TracePageHeader.js @@ -194,6 +194,7 @@ export function TracePageHeaderFn(props: TracePageHeaderProps) { View Options + {archiveButtonVisible && ( + )} +

+ {name || FALLBACK_TRACE_NAME} +

+ + +
+ {enableDetails && + !slimView && } + + ); +} + +// ghetto fabulous cast because the 16.3 API is not in flow yet +// https://github.com/facebook/flow/issues/6103 +export default (React: any).forwardRef((props, ref) => ( + +)); diff --git a/packages/jaeger-ui/src/components/TracePage/TracePageHeaderEmbed.test.js b/packages/jaeger-ui/src/components/TracePage/TracePageHeaderEmbed.test.js new file mode 100644 index 0000000000..e67cc23e55 --- /dev/null +++ b/packages/jaeger-ui/src/components/TracePage/TracePageHeaderEmbed.test.js @@ -0,0 +1,61 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import React from 'react'; +import { shallow, mount } from 'enzyme'; + +import { TracePageHeaderEmbedFn as TracePageHeaderEmbed, HEADER_ITEMS } from './TracePageHeaderEmbed'; +import LabeledList from '../common/LabeledList'; + +describe('', () => { + const defaultProps = { + traceID: 'some-trace-id', + name: 'some-trace-name', + textFilter: '', + updateTextFilter: () => {}, + }; + + let wrapper; + + beforeEach(() => { + wrapper = shallow(); + }); + + it('renders a
', () => { + expect(wrapper.find('header').length).toBe(1); + }); + + it('renders an empty
if no traceID is present', () => { + wrapper = mount(); + expect(wrapper.children().length).toBe(0); + }); + + it('renders the trace title', () => { + const h1 = wrapper.find('h1').first(); + expect(h1.contains(defaultProps.name)).toBeTruthy(); + }); + + it('renders the header items', () => { + wrapper.find('.horizontal .item').forEach((item, i) => { + expect(item.contains(HEADER_ITEMS[i].title)).toBeTruthy(); + expect(item.contains(HEADER_ITEMS[i].renderer(defaultProps.trace))).toBeTruthy(); + }); + }); + + it('show details if queryparam enableDetails', () => { + wrapper.setProps({ enableDetails: true }); + expect(wrapper.find(LabeledList).length).toBe(1); + }); + +}); diff --git a/packages/jaeger-ui/src/components/TracePage/index.js b/packages/jaeger-ui/src/components/TracePage/index.js index a53d1393d0..e14a7ad739 100644 --- a/packages/jaeger-ui/src/components/TracePage/index.js +++ b/packages/jaeger-ui/src/components/TracePage/index.js @@ -20,6 +20,7 @@ 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'; @@ -32,6 +33,7 @@ import { cancel as cancelScroll, scrollBy, scrollTo } from './scroll-page'; import ScrollManager from './ScrollManager'; import SpanGraph from './SpanGraph'; import TracePageHeader from './TracePageHeader'; +import TracePageHeaderEmbed from './TracePageHeaderEmbed'; import { trackSlimHeaderToggle } from './TracePageHeader.track'; import TraceTimelineViewer from './TraceTimelineViewer'; import ErrorMessage from '../common/ErrorMessage'; @@ -40,6 +42,7 @@ import * as jaegerApiActions from '../../actions/jaeger-api'; import { fetchedState } from '../../constants'; import { getTraceName } from '../../model/trace-viewer'; import prefixUrl from '../../utils/prefix-url'; +import { isEmbed } from '../../utils/embedded'; import type { CombokeysHandler, ShortcutCallbacks } from './keyboard-shortcuts'; import type { ViewRange, ViewRangeTimeUpdate } from './types'; @@ -56,8 +59,13 @@ type TracePageProps = { acknowledgeArchive: string => void, fetchTrace: string => void, history: RouterHistory, + searchParams: string, id: string, trace: ?FetchedTrace, + embed?: boolean, + enableDetails?: boolean, + mapCollapsed?: boolean, + fromSearch?: string, }; type TracePageState = { @@ -326,8 +334,21 @@ export class TracePageImpl extends React.PureComponent { + window.open(prefixUrl(`/trace/${this.props.id.toLowerCase()}`), '_blank'); + }; + render() { - const { archiveEnabled, archiveTraceState, trace } = this.props; + const { + archiveEnabled, + archiveTraceState, + trace, + embed, + mapCollapsed, + enableDetails, + searchParams, + fromSearch, + } = this.props; const { slimView, headerHeight, textFilter, viewRange, findMatchesIDs } = this.state; if (!trace || trace.state === fetchedState.LOADING) { return ; @@ -339,33 +360,46 @@ export class TracePageImpl extends React.PureComponent p.serviceName)).size; + const tracePageProps = { + duration, + maxDepth: maxSpanDepth, + name: getTraceName(spans), + numServices: numberOfServices, + numSpans: spans.length, + slimView, + timestamp: startTime, + traceID, + onSlimViewClicked: this.toggleSlimView, + textFilter, + prevResult: this._scrollManager.scrollToPrevVisibleSpan, + nextResult: this._scrollManager.scrollToNextVisibleSpan, + clearSearch: this.clearSearch, + resultCount: findMatchesIDs ? findMatchesIDs.size : 0, + updateTextFilter: this.updateTextFilter, + archiveButtonVisible: archiveEnabled, + onArchiveClicked: this.archiveTrace, + ref: this._searchBar, + }; + + const tracePageEmbedProps = { + searchParams, + fromSearch, + enableDetails, + onGoFullViewClicked: this.goFullView, + }; + return (
{archiveEnabled && ( )}
- - {!slimView && ( + {embed ? ( + + ) : ( + + )} + {((!slimView && !embed) || (embed && !mapCollapsed)) && ( ', () => { expect(cancelScroll.mock.calls).toEqual([[]]); }); + it('no render TracePageHeader if queryparam embed', () => { + wrapper.setProps({ embed: true }); + expect(wrapper.find(TracePageHeader).length).toBe(0); + }); + + it('collapse map if queryparam mapCollapsed', () => { + wrapper.setProps({ mapCollapsed: true, embed: true }); + expect(wrapper.find(SpanGraph).length).toBe(0); + }); + + it('open a window when goFullView is called', () => { + wrapper.setProps({ id: '12345' }); + global.open = jest.fn(); + wrapper.instance().goFullView(); + expect(global.open).toBeCalledWith(prefixUrl('/trace/12345'), '_blank'); + }); + describe('_adjustViewRange()', () => { let instance; let time; @@ -359,6 +378,48 @@ describe('mapStateToProps()', () => { [id]: { data: trace, state: fetchedState.DONE }, }, }, + router: { + location: { + search: '', + }, + }, + config: { + archiveEnabled: false, + }, + archive: {}, + }; + const ownProps = { + match: { + params: { id }, + }, + }; + const props = mapStateToProps(state, ownProps); + expect(props).toEqual({ + id, + archiveEnabled: false, + embed: false, + enableDetails: false, + fromSearch: undefined, + mapCollapsed: false, + archiveTraceState: undefined, + trace: { data: {}, state: fetchedState.DONE }, + }); + }); + + it('maps state to props correctly with query embed', () => { + const id = 'abc'; + const trace = {}; + const state = { + trace: { + traces: { + [id]: { data: trace, state: fetchedState.DONE }, + }, + }, + router: { + location: { + search: 'embed=v0&enableDetails&mapCollapsed&fromSearch=%2Fsearch%3Fend%3D1542902040794000%26limit%3D20%26lookback%3D1h%26maxDuration%26minDuration%26service%3Dproductpage%26start%3D1542898440794000', + }, + }, config: { archiveEnabled: false, }, @@ -373,6 +434,10 @@ describe('mapStateToProps()', () => { expect(props).toEqual({ id, archiveEnabled: false, + embed: true, + enableDetails: true, + fromSearch: '/search?end=1542902040794000&limit=20&lookback=1h&maxDuration&minDuration&service=productpage&start=1542898440794000', + mapCollapsed: true, archiveTraceState: undefined, trace: { data: {}, state: fetchedState.DONE }, }); diff --git a/packages/jaeger-ui/src/utils/embedded/index.js b/packages/jaeger-ui/src/utils/embedded/index.js new file mode 100644 index 0000000000..8c7b185ef1 --- /dev/null +++ b/packages/jaeger-ui/src/utils/embedded/index.js @@ -0,0 +1,25 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import queryString from 'query-string'; + +export const VERSION_API = 'v0'; + +export function isEmbed(query: string) { + const { embed } = queryString.parse(query); + if (embed === VERSION_API) { + return true; + } + return false; +} diff --git a/packages/jaeger-ui/src/utils/embedded/index.test.js b/packages/jaeger-ui/src/utils/embedded/index.test.js new file mode 100644 index 0000000000..f996d9504d --- /dev/null +++ b/packages/jaeger-ui/src/utils/embedded/index.test.js @@ -0,0 +1,32 @@ +// Copyright (c) 2017 Uber Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as embedded from './index'; + +describe('isEmbed', () => { + it('query request a embed component', () => { + const query = 'embed=v0&hideGraph&mapCollapsed'; + expect(embedded.isEmbed(query)).toBeTruthy(); + }); + + it('query request a embed component with an icorrect version', () => { + const query = 'embed=v1&hideGraph&mapCollapsed'; + expect(embedded.isEmbed(query)).toBeFalsy(); + }); + + it('query not request a embed component', () => { + const query = 'hideGraph&mapCollapsed'; + expect(embedded.isEmbed(query)).toBeFalsy(); + }); +});