Skip to content

Commit

Permalink
[APM] Stacktrace heading styles (#26456)
Browse files Browse the repository at this point in the history
* [APM] fixes #23560 by separating frame headers from code preview and only displaying code preview when stackframe has source code context

* [APM] fixes #26239 by checking for valid line number before displaying it

* [APM] Converted CodePreview and Stacktace to typescript and consolidated Stackframe types

* [APM] pull out components and util functions into own files and added tests
  • Loading branch information
ogupte authored Dec 4, 2018
1 parent 53b8b9a commit 754aa25
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
import { px, unit } from '../../../../../../../style/variables';

// @ts-ignore
import Stacktrace from '../../../../../../shared/Stacktrace';
import { Stacktrace } from '../../../../../../shared/Stacktrace';

import { DatabaseContext } from './DatabaseContext';
import { HttpContext } from './HttpContext';
Expand Down Expand Up @@ -85,6 +85,10 @@ export function SpanFlyout({
const dbContext = span.context.db;
const httpContext = span.context.http;
const tagContext = span.context.tags;
const tags = keys(tagContext).map(key => ({
key,
value: get(tagContext, key)
}));

return (
<EuiPortal>
Expand Down Expand Up @@ -140,10 +144,7 @@ export function SpanFlyout({
},
{ field: 'value' }
]}
items={keys(tagContext).map(key => ({
key,
value: get(tagContext, key)
}))}
items={tags}
/>
</Fragment>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import React from 'react';
import { mount } from 'enzyme';

import CodePreview from '../index';
import { CodePreview } from '../index';
import props from './props.json';
import { toJson } from '../../../../utils/testHelpers';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CodePreview should render with data 1`] = `
.c2 {
color: #999999;
padding: 8px;
font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;
}
.c3 {
font-weight: bold;
color: #000000;
}
.c4 {
position: relative;
border-radius: 0 0 5px 5px;
Expand Down Expand Up @@ -85,16 +96,10 @@ exports[`CodePreview should render with data 1`] = `
}
.c1 {
color: #999999;
padding: 8px;
border-bottom: 1px solid #d9d9d9;
border-radius: 5px 5px 0 0;
}
.c3 {
font-weight: bold;
}
.c0 {
margin: 0 0 24px 0;
position: relative;
Expand All @@ -104,36 +109,35 @@ exports[`CodePreview should render with data 1`] = `
background: #f5f5f5;
}
.c0 .c2 {
color: #000000;
}
<div
className="c0"
>
<div
className="c1"
>
<span
className="c2 c3"
>
server/coffee.js
</span>
in
<span
className="c2 c3"
>
&lt;anonymous&gt;
</span>
at
<span
className="c2 c3"
<div
className="c2"
>
line
17
</span>
<span
className="c3"
>
server/coffee.js
</span>
in
<span
className="c3"
>
&lt;anonymous&gt;
</span>
at
<span
className="c3"
>
line
17
</span>
</div>
</div>
<div
className="c4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,86 +7,87 @@
import React, { PureComponent } from 'react';
import styled from 'styled-components';
import {
units,
px,
borderRadius,
colors,
fontFamilyCode,
borderRadius
px,
units
} from '../../../style/variables';

import { isEmpty } from 'lodash';

import { registerLanguage } from 'react-syntax-highlighter/dist/light';
// TODO add dependency for @types/react-syntax-highlighter
// @ts-ignore
import javascript from 'react-syntax-highlighter/dist/languages/javascript';
// @ts-ignore
import python from 'react-syntax-highlighter/dist/languages/python';
// @ts-ignore
import ruby from 'react-syntax-highlighter/dist/languages/ruby';
import { Variables } from './Variables';
// @ts-ignore
import { registerLanguage } from 'react-syntax-highlighter/dist/light';
import { Stackframe } from '../../../../typings/APMDoc';
import { FrameHeading } from '../Stacktrace/FrameHeading';
// @ts-ignore
import { Context } from './Context';
// @ts-ignore
import { Variables } from './Variables';

registerLanguage('javascript', javascript);
registerLanguage('python', python);
registerLanguage('ruby', ruby);

const FileDetails = styled.div`
color: ${colors.gray3};
padding: ${px(units.half)};
const CodeHeader = styled.div`
border-bottom: 1px solid ${colors.gray4};
border-radius: ${borderRadius} ${borderRadius} 0 0;
`;

const FileDetail = styled.span`
font-weight: bold;
`;
interface ContainerProps {
isLibraryFrame?: boolean;
}

const Container = styled.div`
const Container = styled.div<ContainerProps>`
margin: 0 0 ${px(units.plus)} 0;
position: relative;
font-family: ${fontFamilyCode};
border: 1px solid ${colors.gray4};
border-radius: ${borderRadius};
background: ${props => (props.isLibraryFrame ? colors.white : colors.gray5)};
${FileDetails} {
${props => (!props.hasContext ? 'border-bottom: 0' : null)};
}
${FileDetail} {
color: ${props => (props.isLibraryFrame ? colors.gray1 : colors.black)};
}
`;

class CodePreview extends PureComponent {
state = {
interface Props {
isLibraryFrame?: boolean;
codeLanguage?: string;
stackframe: Stackframe;
}

export class CodePreview extends PureComponent<Props> {
public state = {
variablesVisible: false
};

toggleVariables = () =>
public toggleVariables = () =>
this.setState(() => {
return { variablesVisible: !this.state.variablesVisible };
});

render() {
public render() {
const { stackframe, codeLanguage, isLibraryFrame } = this.props;
const hasContext = !(
isEmpty(stackframe.context) && isEmpty(stackframe.line.context)
);
const hasVariables = !isEmpty(stackframe.vars);

return (
<Container hasContext={hasContext} isLibraryFrame={isLibraryFrame}>
<FileDetails>
<FileDetail>{stackframe.filename}</FileDetail> in{' '}
<FileDetail>{stackframe.function}</FileDetail> at{' '}
<FileDetail>line {stackframe.line.number}</FileDetail>
</FileDetails>

{hasContext && (
<Context
<Container isLibraryFrame={isLibraryFrame}>
<CodeHeader>
<FrameHeading
stackframe={stackframe}
codeLanguage={codeLanguage}
isLibraryFrame={isLibraryFrame}
/>
)}
</CodeHeader>

<Context
stackframe={stackframe}
codeLanguage={codeLanguage}
isLibraryFrame={isLibraryFrame}
/>

{hasVariables && (
<Variables
Expand All @@ -99,5 +100,3 @@ class CodePreview extends PureComponent {
);
}
}

export default CodePreview;
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { get } from 'lodash';
import React, { Fragment } from 'react';
import styled from 'styled-components';
import { Stackframe } from '../../../../typings/APMDoc';
import { colors, fontFamilyCode, px, units } from '../../../style/variables';

const FileDetails = styled.div`
color: ${colors.gray3};
padding: ${px(units.half)};
font-family: ${fontFamilyCode};
`;
const LibraryFrameFileDetail = styled.span`
color: ${colors.gray2};
`;
const AppFrameFileDetail = styled.span`
font-weight: bold;
color: ${colors.black};
`;

interface Props {
stackframe: Stackframe;
isLibraryFrame?: boolean;
}

const FrameHeading: React.SFC<Props> = ({
stackframe,
isLibraryFrame = false
}) => {
const FileDetail = isLibraryFrame
? LibraryFrameFileDetail
: AppFrameFileDetail;
const lineNumber: number = get(stackframe, 'line.number');
return (
<FileDetails>
<FileDetail>{stackframe.filename}</FileDetail> in{' '}
<FileDetail>{stackframe.function}</FileDetail>
{lineNumber > 0 && (
<Fragment>
{' at '}
<FileDetail>line {stackframe.line.number}</FileDetail>
</Fragment>
)}
</FileDetails>
);
};

export { FrameHeading };
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiLink } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { Stackframe } from '../../../../typings/APMDoc';
import { px, units } from '../../../style/variables';
import { CodePreview } from '../../shared/CodePreview';
// @ts-ignore
import { Ellipsis } from '../../shared/Icons';
import { FrameHeading } from './FrameHeading';
import { hasSourceLines } from './stacktraceUtils';

const LibraryFrameToggle = styled.div`
margin: 0 0 ${px(units.plus)} 0;
user-select: none;
`;

interface Props {
visible?: boolean;
stackframes: Stackframe[];
codeLanguage?: string;
onClick: () => void;
}

export const LibraryFrames: React.SFC<Props> = ({
visible,
stackframes,
codeLanguage,
onClick
}) => {
return (
<div>
<LibraryFrameToggle>
<EuiLink onClick={onClick}>
<Ellipsis horizontal={visible} style={{ marginRight: units.half }} />{' '}
{stackframes.length} library frames
</EuiLink>
</LibraryFrameToggle>

<div>
{visible &&
stackframes.map(
(stackframe, i) =>
hasSourceLines(stackframe) ? (
<CodePreview
key={i}
stackframe={stackframe}
isLibraryFrame
codeLanguage={codeLanguage}
/>
) : (
<FrameHeading key={i} stackframe={stackframe} isLibraryFrame />
)
)}
</div>
</div>
);
};
Loading

0 comments on commit 754aa25

Please sign in to comment.