Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trace diffs #228

Merged
merged 13 commits into from
Aug 14, 2018
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,4 @@ npm-debug.log
.vscode
.idea
yarn-error.log

lerna-debug\.log
lerna-debug.log
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@ language: node_js
node_js:
- '6'
cache: yarn
env:
global:
# so the yarn installed in before_install will be used
- PATH=$HOME/.yarn/bin:$PATH
before_install:
# update yarn - travis is using an old version
# https://yarnpkg.com/en/docs/install#alternatives-stable
- curl -o- -L https://yarnpkg.com/install.sh | bash
install:
- yarn install --frozen-lockfile
script:
- yarn lint
- yarn coverage
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"lerna": "2.10.2",
"packages": ["packages/*"],
"version": "independent",
"npmClient": "yarn",
"npmClientArgs": ["--pure-lockfile"],
"useWorkspaces": true
}
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
"coverage": "lerna run coverage",
"eslint": "eslint 'scripts/*.js' 'packages/*/src/**/*.js' 'packages/*/*.js'",
"flow": "glow",
"lint": "npm run eslint && npm run prettier && npm run flow && npm run check-license",
"lint": "yarn run eslint && yarn run prettier && yarn run flow && yarn run check-license",
"precommit": "lint-staged",
"prepare": "lerna run --stream --sort prepublishOnly",
"prettier":
"prettier --write '{.,scripts}/*.{js,json,md}' 'packages/*/{src,demo/src}/**/*.{css,js,json,md}' 'packages/*/*.{css,js,json,md}'",
"test": "lerna run test",
Expand All @@ -39,7 +40,7 @@
"trailingComma": "es5"
},
"lint-staged": {
"*.{css,js,json}": ["npm run lint", "npm run test", "git add"],
"*.md": ["npm run prettier", "git add"]
"*.{css,js,json}": ["yarn run lint", "yarn run test", "git add"],
"*.md": ["yarn run prettier", "git add"]
}
}
3 changes: 3 additions & 0 deletions packages/jaeger-ui/config-overrides-antd-vars.less
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@
@layout-zero-trigger-height : 42px;

@menu-dark-bg: #151515;

// Table
@table-row-hover-bg:#e5f2f2;
3 changes: 2 additions & 1 deletion packages/jaeger-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"sinon": "^3.2.1"
},
"dependencies": {
"@jaegertracing/plexus": "0.0.1-dev.3",
"antd": "^3.0.3",
"chance": "^1.0.10",
"classnames": "^2.2.5",
Expand Down Expand Up @@ -77,7 +78,7 @@
},
"scripts": {
"build": "REACT_APP_VSN_STATE=$(../../scripts/get-tracking-version.js) react-app-rewired build",
"coverage": "npm run test -- --coverage",
"coverage": "yarn run test -- --coverage",
"start:ga-debug":
"REACT_APP_GA_DEBUG=1 REACT_APP_VSN_STATE=$(../../scripts/get-tracking-version.js) react-app-rewired start",
"start": "react-app-rewired start",
Expand Down
6 changes: 6 additions & 0 deletions packages/jaeger-ui/src/actions/jaeger-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ export const fetchTrace = createAction(
id => ({ id })
);

export const fetchMultipleTraces = createAction(
'@JAEGER_API/FETCH_MULTIPLE_TRACES',
ids => JaegerAPI.searchTraces({ traceID: ids }),
ids => ({ ids })
);

export const archiveTrace = createAction(
'@JAEGER_API/ARCHIVE_TRACE',
id => JaegerAPI.archiveTrace(id),
Expand Down
32 changes: 14 additions & 18 deletions packages/jaeger-ui/src/components/App/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,58 +22,54 @@ import type { Location } from 'react-router-dom';
import { withRouter } from 'react-router-dom';

import TopNav from './TopNav';
import type { Config } from '../../types/config';
import { trackPageView } from '../../utils/tracking';

import './Page.css';

type PageProps = {
location: Location,
type Props = {
pathname: string,
search: string,
children: React.Node,
config: Config,
};

const { Header, Content } = Layout;

// export for tests
export class PageImpl extends React.Component<PageProps> {
props: PageProps;
export class PageImpl extends React.Component<Props> {
props: Props;

componentDidMount() {
const { pathname, search } = this.props.location;
const { pathname, search } = this.props;
trackPageView(pathname, search);
}

componentWillReceiveProps(nextProps: PageProps) {
const { pathname, search } = this.props.location;
const { pathname: nextPathname, search: nextSearch } = nextProps.location;
componentWillReceiveProps(nextProps: Props) {
const { pathname, search } = this.props;
const { pathname: nextPathname, search: nextSearch } = nextProps;
if (pathname !== nextPathname || search !== nextSearch) {
trackPageView(nextPathname, nextSearch);
}
}

render() {
const { children, config, location } = this.props;
const menu = config && config.menu;
return (
<div>
<Helmet title="Jaeger UI" />
<Layout>
<Header className="Page--topNav">
<TopNav activeKey={location.pathname} menuConfig={menu} />
<TopNav />
</Header>
<Content className="Page--content">{children}</Content>
<Content className="Page--content">{this.props.children}</Content>
</Layout>
</div>
);
}
}

// export for tests
export function mapStateToProps(state: { config: Config, router: { location: Location } }, ownProps: any) {
const { config } = state;
const { location } = state.router;
return { ...ownProps, config, location };
export function mapStateToProps(state: { router: { location: Location } }) {
const { pathname, search } = state.router.location;
return { pathname, search };
}

export default withRouter(connect(mapStateToProps)(PageImpl));
27 changes: 10 additions & 17 deletions packages/jaeger-ui/src/components/App/Page.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,12 @@ import { trackPageView } from '../../utils/tracking';

describe('mapStateToProps()', () => {
it('maps state to props', () => {
const pathname = 'a-pathname';
const search = 'a-search';
const state = {
config: {},
router: { location: {} },
router: { location: { pathname, search } },
};
const ownProps = { a: {} };
expect(mapStateToProps(state, ownProps)).toEqual({
config: state.config,
location: state.router.location,
a: ownProps.a,
});
expect(mapStateToProps(state)).toEqual({ pathname, search });
});
});

Expand All @@ -44,11 +40,8 @@ describe('<Page>', () => {
beforeEach(() => {
trackPageView.mockReset();
props = {
location: {
pathname: String(Math.random()),
search: String(Math.random()),
},
config: { menu: [] },
pathname: String(Math.random()),
search: String(Math.random()),
};
wrapper = mount(<Page {...props} />);
});
Expand All @@ -58,14 +51,14 @@ describe('<Page>', () => {
});

it('tracks an initial page-view', () => {
const { pathname, search } = props.location;
const { pathname, search } = props;
expect(trackPageView.mock.calls).toEqual([[pathname, search]]);
});

it('tracks a pageView when the location changes', () => {
trackPageView.mockReset();
const location = { pathname: 'le-path', search: 'searching' };
wrapper.setProps({ location });
expect(trackPageView.mock.calls).toEqual([[location.pathname, location.search]]);
props = { pathname: 'le-path', search: 'searching' };
wrapper.setProps(props);
expect(trackPageView.mock.calls).toEqual([[props.pathname, props.search]]);
});
});
61 changes: 41 additions & 20 deletions packages/jaeger-ui/src/components/App/TopNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,38 @@

import React from 'react';
import { Dropdown, Icon, Menu } from 'antd';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { Link, withRouter } from 'react-router-dom';

import TraceIDSearchInput from './TraceIDSearchInput';
import type { ConfigMenuItem, ConfigMenuGroup } from '../../types/config';
import * as dependencies from '../DependencyGraph/url';
import * as searchUrl from '../SearchTracePage/url';
import * as diffUrl from '../TraceDiff/url';
import { getConfigValue } from '../../utils/config/get-config';
import prefixUrl from '../../utils/prefix-url';

type TopNavProps = {
activeKey: string,
menuConfig: (ConfigMenuItem | ConfigMenuGroup)[],
};
import type { ReduxState } from '../../types';
import type { ConfigMenuItem, ConfigMenuGroup } from '../../types/config';

type Props = ReduxState;

const NAV_LINKS = [
{
to: prefixUrl('/search'),
to: searchUrl.getUrl(),
matches: searchUrl.matches,
text: 'Search',
},
{
to: (props: Props) => diffUrl.getUrl(props.traceDiff),
matches: diffUrl.matches,
text: 'Compare',
},
];

if (getConfigValue('dependencies.menuEnabled')) {
NAV_LINKS.push({
to: prefixUrl('/dependencies'),
to: dependencies.getUrl(),
matches: dependencies.matches,
text: 'Dependencies',
});
}
Expand Down Expand Up @@ -66,12 +76,13 @@ function CustomNavDropdown({ label, items }: ConfigMenuGroup) {
);
}

export default function TopNav(props: TopNavProps) {
const { activeKey, menuConfig } = props;
const menuItems = Array.isArray(menuConfig) ? menuConfig : [];
export function TopNavImpl(props: Props) {
const { config, router } = props;
const { pathname } = router.location;
const menuItems = Array.isArray(config.menu) ? config.menu : [];
return (
<div>
<Menu theme="dark" mode="horizontal" selectable={false} className="ub-right" selectedKeys={[activeKey]}>
<Menu theme="dark" mode="horizontal" selectable={false} className="ub-right" selectedKeys={[pathname]}>
{menuItems.map(m => {
if (m.items != null) {
const group = ((m: any): ConfigMenuGroup);
Expand All @@ -91,25 +102,35 @@ export default function TopNav(props: TopNavProps) {
);
})}
</Menu>
<Menu theme="dark" mode="horizontal" selectable={false} selectedKeys={[activeKey]}>
<Menu theme="dark" mode="horizontal" selectable={false} selectedKeys={[pathname]}>
<Menu.Item>
<Link to={prefixUrl('/')}>Jaeger UI</Link>
</Menu.Item>
<Menu.Item>
<TraceIDSearchInput />
</Menu.Item>
{NAV_LINKS.map(({ to, text }) => (
<Menu.Item key={to}>
<Link to={to}>{text}</Link>
</Menu.Item>
))}
{NAV_LINKS.map(({ matches, to, text }) => {
const url = typeof to === 'string' ? to : to(props);
const key = matches(pathname) ? pathname : url;
return (
<Menu.Item key={key}>
<Link to={url}>{text}</Link>
</Menu.Item>
);
})}
</Menu>
</div>
);
}

TopNav.defaultProps = {
TopNavImpl.defaultProps = {
menuConfig: [],
};

TopNav.CustomNavDropdown = CustomNavDropdown;
TopNavImpl.CustomNavDropdown = CustomNavDropdown;

function mapStateToProps(state: Props) {
return state;
}

export default withRouter(connect(mapStateToProps)(TopNavImpl));
27 changes: 16 additions & 11 deletions packages/jaeger-ui/src/components/App/TopNav.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import { Link } from 'react-router-dom';

import TopNav from './TopNav';
import { TopNavImpl as TopNav } from './TopNav';

describe('<TopNav>', () => {
const labelGitHub = 'GitHub';
Expand All @@ -34,16 +34,21 @@ describe('<TopNav>', () => {
];

const defaultProps = {
menuConfig: [
{
label: labelGitHub,
url: githubUrl,
},
{
label: labelAbout,
items: dropdownItems,
},
],
config: {
menu: [
{
label: labelGitHub,
url: githubUrl,
},
{
label: labelAbout,
items: dropdownItems,
},
],
},
router: {
location: { location: { pathname: 'some-path ' } },
},
};

let wrapper;
Expand Down
Loading