Skip to content

Commit

Permalink
[ObsUX][APM] Replace react-syntax-highlighter with EuiCodeBlock (e…
Browse files Browse the repository at this point in the history
…lastic#204902)

## Summary

Removes `react-syntax-highlighter` from APM errors, in favour of
`EuiCodeBlock` for read-only code syntax highlighting. This in turn
removes a bunch of custom styling to bring things more inline with the
design system as well.

Closes elastic#204049

## How to test

* Go to Applications - Service Inventory
* Find a service with errors
* Go to Errors tab for service
* Select an error that is an exception
* View details for the exception and see the syntax highlighted block
for the stack trace.
  • Loading branch information
Bluefinger authored Jan 8, 2025
1 parent 5323067 commit 2a7a53a
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 177 deletions.
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,6 @@
"react-router-dom": "^5.3.4",
"react-router-dom-v5-compat": "^6.12.0",
"react-shortcuts": "^2.1.0",
"react-syntax-highlighter": "^15.3.1",
"react-use": "^15.3.8",
"react-virtualized": "^9.22.5",
"react-window": "^1.8.10",
Expand Down Expand Up @@ -1651,7 +1650,6 @@
"@types/react-router": "^5.1.20",
"@types/react-router-config": "^5.0.7",
"@types/react-router-dom": "^5.3.3",
"@types/react-syntax-highlighter": "^15.4.0",
"@types/react-test-renderer": "^17.0.2",
"@types/react-virtualized": "^9.21.30",
"@types/react-window": "^1.8.8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,7 @@ module.exports = {
exclude: /node_modules/,
},
{
test: [
require.resolve('@elastic/eui/es/components/drag_and_drop'),
require.resolve('highlight.js'),
],
test: [require.resolve('@elastic/eui/es/components/drag_and_drop')],
use: require.resolve('null-loader'),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,143 +5,47 @@
* 2.0.
*/

import { size } from 'lodash';
import { tint } from 'polished';
import React from 'react';
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import javascript from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript';
import python from 'react-syntax-highlighter/dist/cjs/languages/hljs/python';
import ruby from 'react-syntax-highlighter/dist/cjs/languages/hljs/ruby';
import xcode from 'react-syntax-highlighter/dist/cjs/styles/hljs/xcode';
import styled from '@emotion/styled';
import { EuiCodeBlock } from '@elastic/eui';
import type { StackframeWithLineContext } from '../../../../typings/es_schemas/raw/fields/stackframe';

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

const ContextContainer = styled.div`
position: relative;
border-radius: ${({ theme }) => theme.euiTheme.border.radius.small};
`;

const LINE_HEIGHT = 18;
const LineHighlight = styled.div<{ lineNumber: number }>`
position: absolute;
width: 100%;
height: ${LINE_HEIGHT}px;
top: ${(props) => props.lineNumber * LINE_HEIGHT}px;
pointer-events: none;
background-color: ${({ theme }) => tint(0.9, theme.euiTheme.colors.warning)};
`;

const LineNumberContainer = styled.div<{ isLibraryFrame: boolean }>`
position: absolute;
top: 0;
left: 0;
border-radius: ${({ theme }) => theme.euiTheme.border.radius.small};
background: ${({ isLibraryFrame, theme }) =>
isLibraryFrame ? theme.euiTheme.colors.emptyShade : theme.euiTheme.colors.lightestShade};
`;

const LineNumber = styled.div<{ highlight: boolean }>`
position: relative;
min-width: 42px;
padding-left: ${({ theme }) => theme.euiTheme.size.s};
padding-right: ${({ theme }) => theme.euiTheme.size.xs};
color: ${({ theme }) => theme.euiTheme.colors.mediumShade};
line-height: ${LINE_HEIGHT}px;
text-align: right;
border-right: ${({ theme }) => theme.euiTheme.border.thin};
background-color: ${({ highlight, theme }) =>
highlight ? tint(0.9, theme.euiTheme.colors.warning) : null};
&:last-of-type {
border-radius: 0 0 0 ${({ theme }) => theme.euiTheme.border.radius.small};
}
`;

const LineContainer = styled.div`
overflow: auto;
margin: 0 0 0 42px;
padding: 0;
background-color: ${({ theme }) => theme.euiTheme.colors.emptyShade};
&:last-of-type {
border-radius: 0 0 ${({ theme }) => theme.euiTheme.border.radius.small} 0;
}
`;

const Line = styled.pre`
// Override all styles
margin: 0;
color: inherit;
background: inherit;
border: 0;
border-radius: 0;
overflow: initial;
padding: 0 ${LINE_HEIGHT}px;
line-height: ${LINE_HEIGHT}px;
`;

const Code = styled.code`
position: relative;
padding: 0;
margin: 0;
white-space: pre;
z-index: 2;
`;

function getStackframeLines(stackframe: StackframeWithLineContext) {
const line = stackframe.line.context;
const preLines = stackframe.context?.pre || [];
const postLines = stackframe.context?.post || [];
return [...preLines, line, ...postLines].map(
(x) => (x.endsWith('\n') ? x.slice(0, -1) : x) || ' '
);
return [...preLines, line, ...postLines]
.map((x) => (x.endsWith('\n') ? x.slice(0, -1) : x) || ' ')
.join('\n');
}

function getStartLineNumber(stackframe: StackframeWithLineContext) {
const preLines = size(stackframe.context?.pre || []);
const preLines = (stackframe.context?.pre || []).length;
return stackframe.line.number - preLines;
}

interface Props {
stackframe: StackframeWithLineContext;
codeLanguage?: string;
isLibraryFrame: boolean;
}

export function Context({ stackframe, codeLanguage, isLibraryFrame }: Props) {
export function Context({ stackframe, codeLanguage }: Props) {
const lines = getStackframeLines(stackframe);
const startLineNumber = getStartLineNumber(stackframe);
const highlightedLineIndex = size(stackframe.context?.pre || []);
const start = getStartLineNumber(stackframe);
const highlightedLine = start + (stackframe.context?.pre || []).length;
const language = codeLanguage || 'javascript'; // TODO: Add support for more languages

return (
<ContextContainer>
<LineHighlight lineNumber={highlightedLineIndex} />
<LineNumberContainer isLibraryFrame={isLibraryFrame}>
{lines.map((line, i) => (
<LineNumber key={line + i} highlight={highlightedLineIndex === i}>
{i + startLineNumber}.
</LineNumber>
))}
</LineNumberContainer>
<LineContainer>
{lines.map((line, i) => (
<SyntaxHighlighter
key={line + i}
language={language}
style={xcode}
PreTag={Line}
CodeTag={Code}
customStyle={{ padding: undefined, overflowX: undefined }}
>
{line}
</SyntaxHighlighter>
))}
</LineContainer>
</ContextContainer>
<EuiCodeBlock
language={language}
whiteSpace="pre"
paddingSize="s"
lineNumbers={{
start,
highlight: `${highlightedLine}`,
}}
transparentBackground
>
{lines}
</EuiCodeBlock>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('Stackframe', () => {
});

it('should have isLibraryFrame=false as default', () => {
expect(wrapper.find('Context').prop('isLibraryFrame')).toBe(false);
expect(wrapper.find('FrameHeading').prop('isLibraryFrame')).toBe(false);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@ import { Context } from './context';
import { FrameHeading } from './frame_heading';
import { Variables } from './variables';

const ContextContainer = styled.div<{ isLibraryFrame: boolean }>`
const ContextContainer = styled.div`
position: relative;
font-family: ${({ theme }) => theme.euiTheme.font.familyCode};
font-size: ${() => useEuiFontSize('s').fontSize};
border: ${({ theme }) => theme.euiTheme.border.thin};
border-radius: ${({ theme }) => theme.euiTheme.border.radius.small};
background: ${({ isLibraryFrame, theme }) =>
isLibraryFrame ? theme.euiTheme.colors.emptyShade : theme.euiTheme.colors.lightestShade};
background: ${({ theme }) => theme.euiTheme.colors.emptyShade};
`;

// Indent the non-context frames the same amount as the accordion control
Expand Down Expand Up @@ -72,12 +71,8 @@ export function Stackframe({
id={id}
initialIsOpen={initialIsOpen}
>
<ContextContainer isLibraryFrame={isLibraryFrame}>
<Context
stackframe={stackframe}
codeLanguage={codeLanguage}
isLibraryFrame={isLibraryFrame}
/>
<ContextContainer>
<Context stackframe={stackframe} codeLanguage={codeLanguage} />
</ContextContainer>
<Variables vars={stackframe.vars} />
</EuiAccordion>
Expand Down
47 changes: 2 additions & 45 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12291,13 +12291,6 @@
"@types/history" "^4.7.11"
"@types/react" "*"

"@types/react-syntax-highlighter@^15.4.0":
version "15.5.5"
resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.5.tgz#4d3b51f8956195f1f63360ff03f8822c5d74c516"
integrity sha512-QH3JZQXa2usAvJvSsdSUJ4Yu4j8ReuZpgRrEW+XP+Rmosbn425YshW9iGEb/pAARm8496axHhHUPRH3UmTiB6A==
dependencies:
"@types/react" "*"

"@types/react-test-renderer@^17.0.2":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-17.0.2.tgz#5f800a39b12ac8d2a2149e7e1885215bcf4edbbf"
Expand Down Expand Up @@ -19110,13 +19103,6 @@ fastq@^1.13.0, fastq@^1.6.0:
dependencies:
reusify "^1.0.4"

fault@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13"
integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==
dependencies:
format "^0.2.0"

faye-websocket@^0.11.3:
version "0.11.3"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
Expand Down Expand Up @@ -19537,11 +19523,6 @@ form-data@^4.0.0, form-data@~4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"

format@^0.2.0:
version "0.2.2"
resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=

formdata-node@^4.3.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2"
Expand Down Expand Up @@ -20707,11 +20688,6 @@ hexoid@^2.0.0:
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-2.0.0.tgz#fb36c740ebbf364403fa1ec0c7efd268460ec5b9"
integrity sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==

highlight.js@^10.1.1, highlight.js@~10.4.0:
version "10.4.1"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0"
integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==

history@^4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca"
Expand Down Expand Up @@ -23730,14 +23706,6 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==

lowlight@^1.14.0:
version "1.17.0"
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.17.0.tgz#a1143b2fba8239df8cd5893f9fe97aaf8465af4a"
integrity sha512-vmtBgYKD+QVNy7tIa7ulz5d//Il9R4MooOVh4nkOf9R9Cb/Dk5TXMSTieg/vDulkBkIWj59/BIlyFQxT9X1oAQ==
dependencies:
fault "^1.0.0"
highlight.js "~10.4.0"

[email protected]:
version "10.2.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
Expand Down Expand Up @@ -27036,7 +27004,7 @@ printj@~1.1.0:
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==

prismjs@^1.22.0, prismjs@^1.29.0:
prismjs@^1.29.0:
version "1.29.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12"
integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==
Expand Down Expand Up @@ -27973,17 +27941,6 @@ react-style-singleton@^2.2.0, react-style-singleton@^2.2.1:
invariant "^2.2.4"
tslib "^2.0.0"

react-syntax-highlighter@^15.3.1:
version "15.3.1"
resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.3.1.tgz#ba16ae8705f191956b73d0e11ae938fd255f2579"
integrity sha512-XVQuug7kQ4/cWxiYE0XfGXvbDqLLqRsMK/GpmD3v1WOLzb6REcgkL59cJo0m3Y2LB0eoRCNhV62jqQe9/Z0p9w==
dependencies:
"@babel/runtime" "^7.3.1"
highlight.js "^10.1.1"
lowlight "^1.14.0"
prismjs "^1.22.0"
refractor "^3.2.0"

react-tabs@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/react-tabs/-/react-tabs-6.0.2.tgz#bc1065c3828561fee285a8fd045f22e0fcdde1eb"
Expand Down Expand Up @@ -28356,7 +28313,7 @@ reflect-metadata@^0.2.2:
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b"
integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==

refractor@^3.2.0, refractor@^3.6.0:
refractor@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a"
integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==
Expand Down

0 comments on commit 2a7a53a

Please sign in to comment.