[APM] Add support for dark mode (#69362)
* Use theme colors for stacktrace * [APM] Use theme for all components * Switch HoC withTheme to useTheme and convert classes to hooks * Change hardcoded white to euiColorEmptyShade for ServiceMap * Snapshots and Legends fix * Switch to context and add test helper * Fix tests and update snaps * New snaps + new anomaly detection * Remove shallow from testHelpers * Remove commented tests * Fix prettier * Pass correct theme to cytoscape * Fix ServiceMap * fixes some rendering issues in service maps * removed the old anomaly detection logic from service map popover contents, since it's been moved to a new component. * Fix eslint, tsc lint issues and unit tests * Remove types for styled-components default theme * Update x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestions.js Co-authored-by: Casper Hübertz <casper@formgeist.com> * fix OuterTheme * Ise function declaration instead of expression Co-authored-by: Balthazar Gronon <git@balthazar.dev> Co-authored-by: Balthazar Gronon <bgronon@gmail.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Oliver Gupte <olivergupte@gmail.com> Co-authored-by: Casper Hübertz <casper@formgeist.com>
This commit is contained in:
parent
a489e5f0b1
commit
84f8b43c38
|
@ -8,8 +8,9 @@ import { ApmRoute } from '@elastic/apm-rum-react';
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Route, Router, Switch } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import { EuiThemeProvider } from '../../../observability/public';
|
||||
import styled, { ThemeProvider, DefaultTheme } from 'styled-components';
|
||||
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
|
||||
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { CoreStart, AppMountParameters } from '../../../../../src/core/public';
|
||||
import { ApmPluginSetupDeps } from '../plugin';
|
||||
import { ApmPluginContext } from '../context/ApmPluginContext';
|
||||
|
@ -41,7 +42,13 @@ const App = () => {
|
|||
const [darkMode] = useUiSetting$<boolean>('theme:darkMode');
|
||||
|
||||
return (
|
||||
<EuiThemeProvider darkMode={darkMode}>
|
||||
<ThemeProvider
|
||||
theme={(outerTheme?: DefaultTheme) => ({
|
||||
...outerTheme,
|
||||
eui: darkMode ? euiDarkVars : euiLightVars,
|
||||
darkMode,
|
||||
})}
|
||||
>
|
||||
<MainContainer data-test-subj="apmMainContainer" role="main">
|
||||
<UpdateBreadcrumbs routes={routes} />
|
||||
<Route component={ScrollToTopOnPathChange} />
|
||||
|
@ -53,7 +60,7 @@ const App = () => {
|
|||
</Switch>
|
||||
</APMIndicesPermission>
|
||||
</MainContainer>
|
||||
</EuiThemeProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import {
|
|||
EuiText,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { Fragment } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
@ -37,7 +36,7 @@ const Titles = styled.div`
|
|||
const Label = styled.div`
|
||||
margin-bottom: ${px(units.quarter)};
|
||||
font-size: ${fontSizes.small};
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
`;
|
||||
|
||||
const Message = styled.div`
|
||||
|
|
|
@ -5,15 +5,14 @@
|
|||
*/
|
||||
|
||||
import { EuiBetaBadge } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const BetaBadgeContainer = styled.div`
|
||||
right: ${theme.gutterTypes.gutterMedium};
|
||||
right: ${({ theme }) => theme.eui.gutterTypes.gutterMedium};
|
||||
position: absolute;
|
||||
top: ${theme.gutterTypes.gutterSmall};
|
||||
top: ${({ theme }) => theme.eui.gutterTypes.gutterSmall};
|
||||
z-index: 1; /* The element containing the cytoscape canvas has z-index = 0. */
|
||||
`;
|
||||
|
||||
|
|
|
@ -4,41 +4,44 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiButtonIcon, EuiPanel, EuiToolTip } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { EuiButtonIcon, EuiPanel, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import styled from 'styled-components';
|
||||
import { CytoscapeContext } from './Cytoscape';
|
||||
import { animationOptions, nodeHeight } from './cytoscapeOptions';
|
||||
import { getAnimationOptions, getNodeHeight } from './cytoscapeOptions';
|
||||
import { getAPMHref } from '../../shared/Links/apm/APMLink';
|
||||
import { useUrlParams } from '../../../hooks/useUrlParams';
|
||||
import { APMQueryParams } from '../../shared/Links/url_helpers';
|
||||
import { useTheme } from '../../../hooks/useTheme';
|
||||
|
||||
const ControlsContainer = styled('div')`
|
||||
left: ${theme.gutterTypes.gutterMedium};
|
||||
left: ${({ theme }) => theme.eui.gutterTypes.gutterMedium};
|
||||
position: absolute;
|
||||
top: ${theme.gutterTypes.gutterSmall};
|
||||
top: ${({ theme }) => theme.eui.gutterTypes.gutterSmall};
|
||||
z-index: 1; /* The element containing the cytoscape canvas has z-index = 0. */
|
||||
`;
|
||||
|
||||
const Button = styled(EuiButtonIcon)`
|
||||
display: block;
|
||||
margin: ${theme.paddingSizes.xs};
|
||||
margin: ${({ theme }) => theme.eui.paddingSizes.xs};
|
||||
`;
|
||||
|
||||
const ZoomInButton = styled(Button)`
|
||||
margin-bottom: ${theme.paddingSizes.s};
|
||||
margin-bottom: ${({ theme }) => theme.eui.paddingSizes.s};
|
||||
`;
|
||||
|
||||
const Panel = styled(EuiPanel)`
|
||||
margin-bottom: ${theme.paddingSizes.s};
|
||||
margin-bottom: ${({ theme }) => theme.eui.paddingSizes.s};
|
||||
`;
|
||||
|
||||
const duration = parseInt(theme.euiAnimSpeedFast, 10);
|
||||
const steps = 5;
|
||||
|
||||
function doZoom(cy: cytoscape.Core | undefined, increment: number) {
|
||||
function doZoom(
|
||||
cy: cytoscape.Core | undefined,
|
||||
increment: number,
|
||||
duration: number
|
||||
) {
|
||||
if (cy) {
|
||||
const level = cy.zoom() + increment;
|
||||
// @ts-ignore `.position()` _does_ work on a NodeCollection. It returns the position of the first element in the collection.
|
||||
|
@ -93,10 +96,12 @@ function useDebugDownloadUrl(cy?: cytoscape.Core) {
|
|||
}
|
||||
|
||||
export function Controls() {
|
||||
const theme = useTheme();
|
||||
const cy = useContext(CytoscapeContext);
|
||||
const { urlParams } = useUrlParams();
|
||||
const currentSearch = urlParams.kuery ?? '';
|
||||
const [zoom, setZoom] = useState((cy && cy.zoom()) || 1);
|
||||
const duration = parseInt(theme.eui.euiAnimSpeedFast, 10);
|
||||
const downloadUrl = useDebugDownloadUrl(cy);
|
||||
|
||||
// Handle zoom events
|
||||
|
@ -120,19 +125,19 @@ export function Controls() {
|
|||
if (cy) {
|
||||
const eles = cy.nodes();
|
||||
cy.animate({
|
||||
...animationOptions,
|
||||
...getAnimationOptions(theme),
|
||||
center: { eles },
|
||||
fit: { eles, padding: nodeHeight },
|
||||
fit: { eles, padding: getNodeHeight(theme) },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function zoomIn() {
|
||||
doZoom(cy, increment);
|
||||
doZoom(cy, increment, duration);
|
||||
}
|
||||
|
||||
function zoomOut() {
|
||||
doZoom(cy, -increment);
|
||||
doZoom(cy, -increment, duration);
|
||||
}
|
||||
|
||||
if (!cy) {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import cytoscape from 'cytoscape';
|
||||
import React, {
|
||||
createContext,
|
||||
CSSProperties,
|
||||
|
@ -13,11 +12,13 @@ import React, {
|
|||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import cytoscape from 'cytoscape';
|
||||
import { debounce } from 'lodash';
|
||||
import { useTheme } from '../../../hooks/useTheme';
|
||||
import {
|
||||
animationOptions,
|
||||
cytoscapeOptions,
|
||||
nodeHeight,
|
||||
getAnimationOptions,
|
||||
getCytoscapeOptions,
|
||||
getNodeHeight,
|
||||
} from './cytoscapeOptions';
|
||||
import { useUiTracker } from '../../../../../observability/public';
|
||||
|
||||
|
@ -73,7 +74,8 @@ function rotatePoint(
|
|||
function getLayoutOptions(
|
||||
selectedRoots: string[],
|
||||
height: number,
|
||||
width: number
|
||||
width: number,
|
||||
nodeHeight: number
|
||||
): cytoscape.LayoutOptions {
|
||||
return {
|
||||
name: 'breadthfirst',
|
||||
|
@ -111,11 +113,14 @@ export function Cytoscape({
|
|||
serviceName,
|
||||
style,
|
||||
}: CytoscapeProps) {
|
||||
const theme = useTheme();
|
||||
const [ref, cy] = useCytoscape({
|
||||
...cytoscapeOptions,
|
||||
...getCytoscapeOptions(theme),
|
||||
elements,
|
||||
});
|
||||
|
||||
const nodeHeight = getNodeHeight(theme);
|
||||
|
||||
// Add the height to the div style. The height is a separate prop because it
|
||||
// is required and can trigger rendering when changed.
|
||||
const divStyle = { ...style, height };
|
||||
|
@ -149,7 +154,7 @@ export function Cytoscape({
|
|||
|
||||
const selectedRoots = selectRoots(event.cy);
|
||||
const layout = cy.layout(
|
||||
getLayoutOptions(selectedRoots, height, width)
|
||||
getLayoutOptions(selectedRoots, height, width, nodeHeight)
|
||||
);
|
||||
|
||||
layout.run();
|
||||
|
@ -162,7 +167,7 @@ export function Cytoscape({
|
|||
layoutstopDelayTimeout = setTimeout(() => {
|
||||
if (serviceName) {
|
||||
event.cy.animate({
|
||||
...animationOptions,
|
||||
...getAnimationOptions(theme),
|
||||
fit: {
|
||||
eles: event.cy.elements(),
|
||||
padding: nodeHeight,
|
||||
|
@ -237,7 +242,16 @@ export function Cytoscape({
|
|||
}
|
||||
clearTimeout(layoutstopDelayTimeout);
|
||||
};
|
||||
}, [cy, elements, height, serviceName, trackApmEvent, width]);
|
||||
}, [
|
||||
cy,
|
||||
elements,
|
||||
height,
|
||||
serviceName,
|
||||
trackApmEvent,
|
||||
width,
|
||||
nodeHeight,
|
||||
theme,
|
||||
]);
|
||||
|
||||
return (
|
||||
<CytoscapeContext.Provider value={cy}>
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { act, render, wait } from '@testing-library/react';
|
||||
import cytoscape from 'cytoscape';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { act, wait } from '@testing-library/react';
|
||||
import cytoscape from 'cytoscape';
|
||||
import { CytoscapeContext } from './Cytoscape';
|
||||
import { EmptyBanner } from './EmptyBanner';
|
||||
import { MockApmPluginContextWrapper } from '../../../context/ApmPluginContext/MockApmPluginContext';
|
||||
import { renderWithTheme } from '../../../utils/testHelpers';
|
||||
|
||||
const cy = cytoscape({});
|
||||
|
||||
|
@ -29,7 +30,7 @@ describe('EmptyBanner', () => {
|
|||
</CytoscapeContext.Provider>
|
||||
</MockApmPluginContextWrapper>
|
||||
);
|
||||
const component = render(<EmptyBanner />, {
|
||||
const component = renderWithTheme(<EmptyBanner />, {
|
||||
wrapper: noCytoscapeWrapper,
|
||||
});
|
||||
|
||||
|
@ -39,7 +40,7 @@ describe('EmptyBanner', () => {
|
|||
|
||||
describe('with no nodes', () => {
|
||||
it('renders null', () => {
|
||||
const component = render(<EmptyBanner />, {
|
||||
const component = renderWithTheme(<EmptyBanner />, {
|
||||
wrapper,
|
||||
});
|
||||
|
||||
|
@ -49,7 +50,7 @@ describe('EmptyBanner', () => {
|
|||
|
||||
describe('with one node', () => {
|
||||
it('does not render null', async () => {
|
||||
const component = render(<EmptyBanner />, { wrapper });
|
||||
const component = renderWithTheme(<EmptyBanner />, { wrapper });
|
||||
|
||||
await act(async () => {
|
||||
cy.add({ data: { id: 'test id' } });
|
||||
|
|
|
@ -4,26 +4,27 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { EuiCallOut } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import styled from 'styled-components';
|
||||
import { ElasticDocsLink } from '../../shared/Links/ElasticDocsLink';
|
||||
import { CytoscapeContext } from './Cytoscape';
|
||||
import { useTheme } from '../../../hooks/useTheme';
|
||||
|
||||
const EmptyBannerContainer = styled.div`
|
||||
margin: ${lightTheme.gutterTypes.gutterSmall};
|
||||
margin: ${({ theme }) => theme.eui.gutterTypes.gutterSmall};
|
||||
/* Add some extra margin so it displays to the right of the controls. */
|
||||
left: calc(
|
||||
${lightTheme.gutterTypes.gutterExtraLarge} +
|
||||
${lightTheme.gutterTypes.gutterSmall}
|
||||
${({ theme }) => theme.eui.gutterTypes.gutterExtraLarge} +
|
||||
${({ theme }) => theme.eui.gutterTypes.gutterSmall}
|
||||
);
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
export function EmptyBanner() {
|
||||
const theme = useTheme();
|
||||
const cy = useContext(CytoscapeContext);
|
||||
const [nodeCount, setNodeCount] = useState(0);
|
||||
|
||||
|
@ -51,8 +52,8 @@ export function EmptyBanner() {
|
|||
// subtract the space for controls and margins.
|
||||
const width =
|
||||
cy.width() -
|
||||
parseInt(lightTheme.gutterTypes.gutterExtraLarge, 10) -
|
||||
parseInt(lightTheme.gutterTypes.gutterLarge, 10);
|
||||
parseInt(theme.eui.gutterTypes.gutterExtraLarge, 10) -
|
||||
parseInt(theme.eui.gutterTypes.gutterLarge, 10);
|
||||
|
||||
return (
|
||||
<EmptyBannerContainer style={{ width }}>
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React from 'react';
|
||||
import { EuiProgress, EuiText, EuiSpacer } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
|
@ -22,7 +21,7 @@ const Overlay = styled.div`
|
|||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: ${theme.gutterTypes.gutterMedium};
|
||||
padding: ${({ theme }) => theme.eui.gutterTypes.gutterMedium};
|
||||
`;
|
||||
|
||||
const ProgressBarContainer = styled.div`
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import cytoscape from 'cytoscape';
|
||||
import React from 'react';
|
||||
|
@ -19,7 +18,7 @@ const ItemRow = styled.div`
|
|||
`;
|
||||
|
||||
const ItemTitle = styled.dt`
|
||||
color: ${lightTheme.textColors.subdued};
|
||||
color: ${({ theme }) => theme.eui.textColors.subdued};
|
||||
`;
|
||||
|
||||
const ItemDescription = styled.dd``;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isNumber } from 'lodash';
|
||||
import React from 'react';
|
||||
|
@ -30,7 +29,7 @@ export const ItemRow = styled('tr')`
|
|||
`;
|
||||
|
||||
export const ItemTitle = styled('td')`
|
||||
color: ${lightTheme.textColors.subdued};
|
||||
color: ${({ theme }) => theme.eui.textColors.subdued};
|
||||
padding-right: 1rem;
|
||||
`;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
|
@ -15,6 +14,7 @@ import {
|
|||
EuiIconTip,
|
||||
EuiHealth,
|
||||
} from '@elastic/eui';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import { fontSize, px } from '../../../../style/variables';
|
||||
import { asInteger } from '../../../../utils/formatters';
|
||||
import { MLJobLink } from '../../../shared/Links/MachineLearningLinks/MLJobLink';
|
||||
|
@ -33,11 +33,11 @@ const VerticallyCentered = styled.div`
|
|||
`;
|
||||
|
||||
const SubduedText = styled.span`
|
||||
color: ${theme.euiTextSubduedColor};
|
||||
color: ${({ theme }) => theme.eui.euiTextSubduedColor};
|
||||
`;
|
||||
|
||||
const EnableText = styled.section`
|
||||
color: ${theme.euiTextSubduedColor};
|
||||
color: ${({ theme }) => theme.eui.euiTextSubduedColor};
|
||||
line-height: 1.4;
|
||||
font-size: ${fontSize};
|
||||
width: ${px(popoverMinWidth)};
|
||||
|
@ -52,6 +52,7 @@ interface AnomalyDetectionProps {
|
|||
}
|
||||
|
||||
export function AnomalyDetection({ serviceNodeData }: AnomalyDetectionProps) {
|
||||
const theme = useTheme();
|
||||
const anomalySeverity = serviceNodeData.anomaly_severity;
|
||||
const anomalyScore = serviceNodeData.anomaly_score;
|
||||
const actualValue = serviceNodeData.actual_value;
|
||||
|
@ -81,7 +82,7 @@ export function AnomalyDetection({ serviceNodeData }: AnomalyDetectionProps) {
|
|||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<VerticallyCentered>
|
||||
<EuiHealth color={getSeverityColor(anomalySeverity)} />
|
||||
<EuiHealth color={getSeverityColor(theme, anomalySeverity)} />
|
||||
<SubduedText>{ANOMALY_DETECTION_SCORE_METRIC}</SubduedText>
|
||||
</VerticallyCentered>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiPopover } from '@elastic/eui';
|
||||
import cytoscape from 'cytoscape';
|
||||
import React, {
|
||||
CSSProperties,
|
||||
MouseEvent,
|
||||
|
@ -15,9 +13,12 @@ import React, {
|
|||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { EuiPopover } from '@elastic/eui';
|
||||
import cytoscape from 'cytoscape';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames';
|
||||
import { CytoscapeContext } from '../Cytoscape';
|
||||
import { animationOptions } from '../cytoscapeOptions';
|
||||
import { getAnimationOptions } from '../cytoscapeOptions';
|
||||
import { Contents } from './Contents';
|
||||
|
||||
interface PopoverProps {
|
||||
|
@ -25,6 +26,7 @@ interface PopoverProps {
|
|||
}
|
||||
|
||||
export function Popover({ focusedServiceName }: PopoverProps) {
|
||||
const theme = useTheme();
|
||||
const cy = useContext(CytoscapeContext);
|
||||
const [selectedNode, setSelectedNode] = useState<
|
||||
cytoscape.NodeSingular | undefined
|
||||
|
@ -93,16 +95,20 @@ export function Popover({ focusedServiceName }: PopoverProps) {
|
|||
event.preventDefault();
|
||||
if (cy) {
|
||||
cy.animate({
|
||||
...animationOptions,
|
||||
...getAnimationOptions(theme),
|
||||
center: { eles: cy.getElementById(selectedNodeServiceName) },
|
||||
});
|
||||
}
|
||||
},
|
||||
[cy, selectedNodeServiceName]
|
||||
[cy, selectedNodeServiceName, theme]
|
||||
);
|
||||
|
||||
const isAlreadyFocused = focusedServiceName === selectedNodeServiceName;
|
||||
|
||||
const onFocusClick = isAlreadyFocused
|
||||
? centerSelectedNode
|
||||
: (_event: MouseEvent<HTMLAnchorElement>) => deselect();
|
||||
|
||||
return (
|
||||
<EuiPopover
|
||||
anchorPosition={'upCenter'}
|
||||
|
@ -115,9 +121,7 @@ export function Popover({ focusedServiceName }: PopoverProps) {
|
|||
<Contents
|
||||
isService={isService}
|
||||
label={label}
|
||||
onFocusClick={
|
||||
isAlreadyFocused ? centerSelectedNode : (_event) => deselect()
|
||||
}
|
||||
onFocusClick={onFocusClick}
|
||||
selectedNodeData={selectedNodeData}
|
||||
selectedNodeServiceName={selectedNodeServiceName}
|
||||
/>
|
||||
|
|
|
@ -3,46 +3,49 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import cytoscape from 'cytoscape';
|
||||
import { CSSProperties } from 'react';
|
||||
import {
|
||||
SERVICE_NAME,
|
||||
SPAN_DESTINATION_SERVICE_RESOURCE,
|
||||
} from '../../../../common/elasticsearch_fieldnames';
|
||||
import { EuiTheme } from '../../../../../observability/public';
|
||||
import { severity } from '../../../../common/ml_job_constants';
|
||||
import { defaultIcon, iconForNode } from './icons';
|
||||
|
||||
export const popoverMinWidth = 280;
|
||||
|
||||
export const getSeverityColor = (nodeSeverity?: string) => {
|
||||
export function getSeverityColor(theme: EuiTheme, nodeSeverity?: string) {
|
||||
switch (nodeSeverity) {
|
||||
case severity.warning:
|
||||
return theme.euiColorVis0;
|
||||
return theme.eui.euiColorVis0;
|
||||
case severity.minor:
|
||||
case severity.major:
|
||||
return theme.euiColorVis5;
|
||||
return theme.eui.euiColorVis5;
|
||||
case severity.critical:
|
||||
return theme.euiColorVis9;
|
||||
return theme.eui.euiColorVis9;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const getBorderColor: cytoscape.Css.MapperFunction<
|
||||
cytoscape.NodeSingular,
|
||||
string
|
||||
> = (el: cytoscape.NodeSingular) => {
|
||||
const hasAnomalyDetectionJob = el.data('ml_job_id') !== undefined;
|
||||
const nodeSeverity = el.data('anomaly_severity');
|
||||
if (hasAnomalyDetectionJob) {
|
||||
return getSeverityColor(nodeSeverity) || theme.euiColorMediumShade;
|
||||
}
|
||||
if (el.hasClass('primary') || el.selected()) {
|
||||
return theme.euiColorPrimary;
|
||||
}
|
||||
return theme.euiColorMediumShade;
|
||||
};
|
||||
function getBorderColorFn(
|
||||
theme: EuiTheme
|
||||
): cytoscape.Css.MapperFunction<cytoscape.NodeSingular, string> {
|
||||
return (el: cytoscape.NodeSingular) => {
|
||||
const hasAnomalyDetectionJob = el.data('ml_job_id') !== undefined;
|
||||
const nodeSeverity = el.data('anomaly_severity');
|
||||
if (hasAnomalyDetectionJob) {
|
||||
return (
|
||||
getSeverityColor(theme, nodeSeverity) || theme.eui.euiColorMediumShade
|
||||
);
|
||||
}
|
||||
if (el.hasClass('primary') || el.selected()) {
|
||||
return theme.eui.euiColorPrimary;
|
||||
}
|
||||
return theme.eui.euiColorMediumShade;
|
||||
};
|
||||
}
|
||||
|
||||
const getBorderStyle: cytoscape.Css.MapperFunction<
|
||||
cytoscape.NodeSingular,
|
||||
|
@ -56,7 +59,7 @@ const getBorderStyle: cytoscape.Css.MapperFunction<
|
|||
}
|
||||
};
|
||||
|
||||
const getBorderWidth = (el: cytoscape.NodeSingular) => {
|
||||
function getBorderWidth(el: cytoscape.NodeSingular) {
|
||||
const nodeSeverity = el.data('anomaly_severity');
|
||||
|
||||
if (nodeSeverity === severity.minor || nodeSeverity === severity.major) {
|
||||
|
@ -66,7 +69,7 @@ const getBorderWidth = (el: cytoscape.NodeSingular) => {
|
|||
} else {
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// IE 11 does not properly load some SVGs or draw certain shapes. This causes
|
||||
// a runtime error and the map fails work at all. We would prefer to do some
|
||||
|
@ -79,172 +82,183 @@ const getBorderWidth = (el: cytoscape.NodeSingular) => {
|
|||
// @ts-ignore `documentMode` is not recognized as a valid property of `document`.
|
||||
const isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
|
||||
|
||||
export const animationOptions: cytoscape.AnimationOptions = {
|
||||
duration: parseInt(theme.euiAnimSpeedNormal, 10),
|
||||
export const getAnimationOptions = (
|
||||
theme: EuiTheme
|
||||
): cytoscape.AnimationOptions => ({
|
||||
duration: parseInt(theme.eui.euiAnimSpeedNormal, 10),
|
||||
// @ts-ignore The cubic-bezier options here are not recognized by the cytoscape types
|
||||
easing: theme.euiAnimSlightBounce,
|
||||
};
|
||||
const lineColor = '#C5CCD7';
|
||||
easing: theme.eui.euiAnimSlightBounce,
|
||||
});
|
||||
|
||||
const zIndexNode = 200;
|
||||
const zIndexEdge = 100;
|
||||
const zIndexEdgeHighlight = 110;
|
||||
const zIndexEdgeHover = 120;
|
||||
export const nodeHeight = parseInt(theme.avatarSizing.l.size, 10);
|
||||
|
||||
export const getNodeHeight = (theme: EuiTheme): number =>
|
||||
parseInt(theme.eui.avatarSizing.l.size, 10);
|
||||
|
||||
function isService(el: cytoscape.NodeSingular) {
|
||||
return el.data(SERVICE_NAME) !== undefined;
|
||||
}
|
||||
|
||||
const style: cytoscape.Stylesheet[] = [
|
||||
{
|
||||
selector: 'node',
|
||||
style: {
|
||||
'background-color': 'white',
|
||||
// The DefinitelyTyped definitions don't specify that a function can be
|
||||
// used here.
|
||||
//
|
||||
// @ts-ignore
|
||||
'background-image': isIE11
|
||||
? undefined
|
||||
: (el: cytoscape.NodeSingular) => iconForNode(el) ?? defaultIcon,
|
||||
'background-height': (el: cytoscape.NodeSingular) =>
|
||||
isService(el) ? '60%' : '40%',
|
||||
'background-width': (el: cytoscape.NodeSingular) =>
|
||||
isService(el) ? '60%' : '40%',
|
||||
'border-color': getBorderColor,
|
||||
'border-style': getBorderStyle,
|
||||
'border-width': getBorderWidth,
|
||||
color: (el: cytoscape.NodeSingular) =>
|
||||
el.hasClass('primary') || el.selected()
|
||||
? theme.euiColorPrimaryText
|
||||
: theme.textColors.text,
|
||||
// theme.euiFontFamily doesn't work here for some reason, so we're just
|
||||
// specifying a subset of the fonts for the label text.
|
||||
'font-family': 'Inter UI, Segoe UI, Helvetica, Arial, sans-serif',
|
||||
'font-size': theme.euiFontSizeS,
|
||||
ghost: 'yes',
|
||||
'ghost-offset-x': 0,
|
||||
'ghost-offset-y': 2,
|
||||
'ghost-opacity': 0.15,
|
||||
height: nodeHeight,
|
||||
label: (el: cytoscape.NodeSingular) =>
|
||||
isService(el)
|
||||
? el.data(SERVICE_NAME)
|
||||
: el.data(SPAN_DESTINATION_SERVICE_RESOURCE),
|
||||
'min-zoomed-font-size': parseInt(theme.euiSizeS, 10),
|
||||
'overlay-opacity': 0,
|
||||
shape: (el: cytoscape.NodeSingular) =>
|
||||
isService(el) ? (isIE11 ? 'rectangle' : 'ellipse') : 'diamond',
|
||||
'text-background-color': theme.euiColorPrimary,
|
||||
'text-background-opacity': (el: cytoscape.NodeSingular) =>
|
||||
el.hasClass('primary') || el.selected() ? 0.1 : 0,
|
||||
'text-background-padding': theme.paddingSizes.xs,
|
||||
'text-background-shape': 'roundrectangle',
|
||||
'text-margin-y': parseInt(theme.paddingSizes.s, 10),
|
||||
'text-max-width': '200px',
|
||||
'text-valign': 'bottom',
|
||||
'text-wrap': 'ellipsis',
|
||||
width: theme.avatarSizing.l.size,
|
||||
'z-index': zIndexNode,
|
||||
const getStyle = (theme: EuiTheme): cytoscape.Stylesheet[] => {
|
||||
const lineColor = theme.eui.euiColorMediumShade;
|
||||
return [
|
||||
{
|
||||
selector: 'node',
|
||||
style: {
|
||||
'background-color': theme.eui.euiColorGhost,
|
||||
// The DefinitelyTyped definitions don't specify that a function can be
|
||||
// used here.
|
||||
//
|
||||
// @ts-ignore
|
||||
'background-image': isIE11
|
||||
? undefined
|
||||
: (el: cytoscape.NodeSingular) => iconForNode(el) ?? defaultIcon,
|
||||
'background-height': (el: cytoscape.NodeSingular) =>
|
||||
isService(el) ? '60%' : '40%',
|
||||
'background-width': (el: cytoscape.NodeSingular) =>
|
||||
isService(el) ? '60%' : '40%',
|
||||
'border-color': getBorderColorFn(theme),
|
||||
'border-style': getBorderStyle,
|
||||
'border-width': getBorderWidth,
|
||||
color: (el: cytoscape.NodeSingular) =>
|
||||
el.hasClass('primary') || el.selected()
|
||||
? theme.eui.euiColorPrimaryText
|
||||
: theme.eui.textColors.text,
|
||||
// theme.euiFontFamily doesn't work here for some reason, so we're just
|
||||
// specifying a subset of the fonts for the label text.
|
||||
'font-family': 'Inter UI, Segoe UI, Helvetica, Arial, sans-serif',
|
||||
'font-size': theme.eui.euiFontSizeS,
|
||||
ghost: 'yes',
|
||||
'ghost-offset-x': 0,
|
||||
'ghost-offset-y': 2,
|
||||
'ghost-opacity': 0.15,
|
||||
height: getNodeHeight(theme),
|
||||
label: (el: cytoscape.NodeSingular) =>
|
||||
isService(el)
|
||||
? el.data(SERVICE_NAME)
|
||||
: el.data(SPAN_DESTINATION_SERVICE_RESOURCE),
|
||||
'min-zoomed-font-size': parseInt(theme.eui.euiSizeS, 10),
|
||||
'overlay-opacity': 0,
|
||||
shape: (el: cytoscape.NodeSingular) =>
|
||||
isService(el) ? (isIE11 ? 'rectangle' : 'ellipse') : 'diamond',
|
||||
'text-background-color': theme.eui.euiColorPrimary,
|
||||
'text-background-opacity': (el: cytoscape.NodeSingular) =>
|
||||
el.hasClass('primary') || el.selected() ? 0.1 : 0,
|
||||
'text-background-padding': theme.eui.paddingSizes.xs,
|
||||
'text-background-shape': 'roundrectangle',
|
||||
'text-margin-y': parseInt(theme.eui.paddingSizes.s, 10),
|
||||
'text-max-width': '200px',
|
||||
'text-valign': 'bottom',
|
||||
'text-wrap': 'ellipsis',
|
||||
width: theme.eui.avatarSizing.l.size,
|
||||
'z-index': zIndexNode,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'edge',
|
||||
style: {
|
||||
'curve-style': 'taxi',
|
||||
// @ts-ignore
|
||||
'taxi-direction': 'auto',
|
||||
'line-color': lineColor,
|
||||
'overlay-opacity': 0,
|
||||
'target-arrow-color': lineColor,
|
||||
'target-arrow-shape': isIE11 ? 'none' : 'triangle',
|
||||
// The DefinitelyTyped definitions don't specify this property since it's
|
||||
// fairly new.
|
||||
//
|
||||
// @ts-ignore
|
||||
'target-distance-from-node': isIE11 ? undefined : theme.paddingSizes.xs,
|
||||
width: 1,
|
||||
'source-arrow-shape': 'none',
|
||||
'z-index': zIndexEdge,
|
||||
{
|
||||
selector: 'edge',
|
||||
style: {
|
||||
'curve-style': 'taxi',
|
||||
// @ts-ignore
|
||||
'taxi-direction': 'auto',
|
||||
'line-color': lineColor,
|
||||
'overlay-opacity': 0,
|
||||
'target-arrow-color': lineColor,
|
||||
'target-arrow-shape': isIE11 ? 'none' : 'triangle',
|
||||
// The DefinitelyTyped definitions don't specify this property since it's
|
||||
// fairly new.
|
||||
//
|
||||
// @ts-ignore
|
||||
'target-distance-from-node': isIE11
|
||||
? undefined
|
||||
: theme.eui.paddingSizes.xs,
|
||||
width: 1,
|
||||
'source-arrow-shape': 'none',
|
||||
'z-index': zIndexEdge,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'edge[bidirectional]',
|
||||
style: {
|
||||
'source-arrow-shape': isIE11 ? 'none' : 'triangle',
|
||||
'source-arrow-color': lineColor,
|
||||
'target-arrow-shape': isIE11 ? 'none' : 'triangle',
|
||||
// @ts-ignore
|
||||
'source-distance-from-node': isIE11
|
||||
? undefined
|
||||
: parseInt(theme.paddingSizes.xs, 10),
|
||||
'target-distance-from-node': isIE11
|
||||
? undefined
|
||||
: parseInt(theme.paddingSizes.xs, 10),
|
||||
{
|
||||
selector: 'edge[bidirectional]',
|
||||
style: {
|
||||
'source-arrow-shape': isIE11 ? 'none' : 'triangle',
|
||||
'source-arrow-color': lineColor,
|
||||
'target-arrow-shape': isIE11 ? 'none' : 'triangle',
|
||||
// @ts-ignore
|
||||
'source-distance-from-node': isIE11
|
||||
? undefined
|
||||
: parseInt(theme.eui.paddingSizes.xs, 10),
|
||||
'target-distance-from-node': isIE11
|
||||
? undefined
|
||||
: parseInt(theme.eui.paddingSizes.xs, 10),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'edge[isInverseEdge]',
|
||||
// @ts-ignore DefinitelyTyped says visibility is "none" but it's
|
||||
// actually "hidden"
|
||||
style: { visibility: 'hidden' },
|
||||
},
|
||||
{
|
||||
selector: 'edge.nodeHover',
|
||||
style: {
|
||||
width: 2,
|
||||
// @ts-ignore
|
||||
'z-index': zIndexEdgeHover,
|
||||
'line-color': theme.euiColorDarkShade,
|
||||
'source-arrow-color': theme.euiColorDarkShade,
|
||||
'target-arrow-color': theme.euiColorDarkShade,
|
||||
{
|
||||
selector: 'edge[isInverseEdge]',
|
||||
// @ts-ignore DefinitelyTyped says visibility is "none" but it's
|
||||
// actually "hidden"
|
||||
style: { visibility: 'hidden' },
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'node.hover',
|
||||
style: {
|
||||
'border-width': getBorderWidth,
|
||||
{
|
||||
selector: 'edge.nodeHover',
|
||||
style: {
|
||||
width: 4,
|
||||
// @ts-ignore
|
||||
'z-index': zIndexEdgeHover,
|
||||
'line-color': theme.eui.euiColorDarkShade,
|
||||
'source-arrow-color': theme.eui.euiColorDarkShade,
|
||||
'target-arrow-color': theme.eui.euiColorDarkShade,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: 'edge.highlight',
|
||||
style: {
|
||||
width: 2,
|
||||
'line-color': theme.euiColorPrimary,
|
||||
'source-arrow-color': theme.euiColorPrimary,
|
||||
'target-arrow-color': theme.euiColorPrimary,
|
||||
// @ts-ignore
|
||||
'z-index': zIndexEdgeHighlight,
|
||||
{
|
||||
selector: 'node.hover',
|
||||
style: {
|
||||
'border-width': getBorderWidth,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
selector: 'edge.highlight',
|
||||
style: {
|
||||
width: 4,
|
||||
'line-color': theme.eui.euiColorPrimary,
|
||||
'source-arrow-color': theme.eui.euiColorPrimary,
|
||||
'target-arrow-color': theme.eui.euiColorPrimary,
|
||||
// @ts-ignore
|
||||
'z-index': zIndexEdgeHighlight,
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// The CSS styles for the div containing the cytoscape element. Makes a
|
||||
// background grid of dots.
|
||||
export const cytoscapeDivStyle: CSSProperties = {
|
||||
export const getCytoscapeDivStyle = (theme: EuiTheme): CSSProperties => ({
|
||||
background: `linear-gradient(
|
||||
90deg,
|
||||
${theme.euiPageBackgroundColor}
|
||||
calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)),
|
||||
${theme.eui.euiPageBackgroundColor}
|
||||
calc(${theme.eui.euiSizeL} - calc(${theme.eui.euiSizeXS} / 2)),
|
||||
transparent 1%
|
||||
)
|
||||
center,
|
||||
linear-gradient(
|
||||
${theme.euiPageBackgroundColor}
|
||||
calc(${theme.euiSizeL} - calc(${theme.euiSizeXS} / 2)),
|
||||
${theme.eui.euiPageBackgroundColor}
|
||||
calc(${theme.eui.euiSizeL} - calc(${theme.eui.euiSizeXS} / 2)),
|
||||
transparent 1%
|
||||
)
|
||||
center,
|
||||
${theme.euiColorLightShade}`,
|
||||
backgroundSize: `${theme.euiSizeL} ${theme.euiSizeL}`,
|
||||
margin: `-${theme.gutterTypes.gutterLarge}`,
|
||||
${theme.eui.euiColorLightShade}`,
|
||||
backgroundSize: `${theme.eui.euiSizeL} ${theme.eui.euiSizeL}`,
|
||||
margin: `-${theme.eui.gutterTypes.gutterLarge}`,
|
||||
marginTop: 0,
|
||||
};
|
||||
});
|
||||
|
||||
export const cytoscapeOptions: cytoscape.CytoscapeOptions = {
|
||||
export const getCytoscapeOptions = (
|
||||
theme: EuiTheme
|
||||
): cytoscape.CytoscapeOptions => ({
|
||||
autoungrabify: true,
|
||||
boxSelectionEnabled: false,
|
||||
maxZoom: 3,
|
||||
minZoom: 0.2,
|
||||
style,
|
||||
};
|
||||
style: getStyle(theme),
|
||||
});
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { useTheme } from '../../../hooks/useTheme';
|
||||
import {
|
||||
invalidLicenseMessage,
|
||||
isValidPlatinumLicense,
|
||||
|
@ -18,7 +18,7 @@ import { callApmApi } from '../../../services/rest/createCallApmApi';
|
|||
import { LicensePrompt } from '../../shared/LicensePrompt';
|
||||
import { Controls } from './Controls';
|
||||
import { Cytoscape } from './Cytoscape';
|
||||
import { cytoscapeDivStyle } from './cytoscapeOptions';
|
||||
import { getCytoscapeDivStyle } from './cytoscapeOptions';
|
||||
import { EmptyBanner } from './EmptyBanner';
|
||||
import { Popover } from './Popover';
|
||||
import { useRefDimensions } from './useRefDimensions';
|
||||
|
@ -29,7 +29,8 @@ interface ServiceMapProps {
|
|||
serviceName?: string;
|
||||
}
|
||||
|
||||
export function ServiceMap({ serviceName }: ServiceMapProps) {
|
||||
export const ServiceMap = ({ serviceName }: ServiceMapProps) => {
|
||||
const theme = useTheme();
|
||||
const license = useLicense();
|
||||
const { urlParams } = useUrlParams();
|
||||
|
||||
|
@ -67,14 +68,16 @@ export function ServiceMap({ serviceName }: ServiceMapProps) {
|
|||
|
||||
return isValidPlatinumLicense(license) ? (
|
||||
<div
|
||||
style={{ height: height - parseInt(theme.gutterTypes.gutterLarge, 10) }}
|
||||
style={{
|
||||
height: height - parseInt(theme.eui.gutterTypes.gutterLarge, 10),
|
||||
}}
|
||||
ref={ref}
|
||||
>
|
||||
<Cytoscape
|
||||
elements={data?.elements ?? []}
|
||||
height={height}
|
||||
serviceName={serviceName}
|
||||
style={cytoscapeDivStyle}
|
||||
style={getCytoscapeDivStyle(theme)}
|
||||
width={width}
|
||||
>
|
||||
<Controls />
|
||||
|
@ -98,4 +101,4 @@ export function ServiceMap({ serviceName }: ServiceMapProps) {
|
|||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
EuiButtonIcon,
|
||||
} from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { useTheme } from '../../../../../hooks/useTheme';
|
||||
import { FETCH_STATUS } from '../../../../../hooks/useFetcher';
|
||||
import { ITableColumn, ManagedTable } from '../../../../shared/ManagedTable';
|
||||
import { LoadingStatePrompt } from '../../../../shared/LoadingStatePrompt';
|
||||
|
@ -32,15 +32,14 @@ import { ConfirmDeleteModal } from './ConfirmDeleteModal';
|
|||
|
||||
type Config = AgentConfigurationListAPIResponse[0];
|
||||
|
||||
export function AgentConfigurationList({
|
||||
status,
|
||||
data,
|
||||
refetch,
|
||||
}: {
|
||||
interface Props {
|
||||
status: FETCH_STATUS;
|
||||
data: Config[];
|
||||
refetch: () => void;
|
||||
}) {
|
||||
}
|
||||
|
||||
export const AgentConfigurationList = ({ status, data, refetch }: Props) => {
|
||||
const theme = useTheme();
|
||||
const [configToBeDeleted, setConfigToBeDeleted] = useState<Config | null>(
|
||||
null
|
||||
);
|
||||
|
@ -128,7 +127,9 @@ export function AgentConfigurationList({
|
|||
)
|
||||
}
|
||||
>
|
||||
<EuiHealth color={isApplied ? 'success' : theme.euiColorLightShade} />
|
||||
<EuiHealth
|
||||
color={isApplied ? 'success' : theme.eui.euiColorLightShade}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
),
|
||||
},
|
||||
|
@ -218,4 +219,4 @@ export function AgentConfigurationList({
|
|||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
import { EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { tint } from 'polished';
|
||||
import React, { Fragment } from 'react';
|
||||
|
@ -33,9 +32,9 @@ registerLanguage('sql', sql);
|
|||
|
||||
const DatabaseStatement = styled.div`
|
||||
padding: ${px(units.half)} ${px(unit)};
|
||||
background: ${tint(0.1, theme.euiColorWarning)};
|
||||
background: ${({ theme }) => tint(0.1, theme.eui.euiColorWarning)};
|
||||
border-radius: ${borderRadius};
|
||||
border: 1px solid ${theme.euiColorLightShade};
|
||||
border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
font-family: ${fontFamilyCode};
|
||||
font-size: ${fontSize};
|
||||
`;
|
||||
|
|
|
@ -8,7 +8,6 @@ import React, { Fragment } from 'react';
|
|||
import styled from 'styled-components';
|
||||
|
||||
import { EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import {
|
||||
borderRadius,
|
||||
fontFamilyCode,
|
||||
|
@ -21,9 +20,9 @@ import { Span } from '../../../../../../../../typings/es_schemas/ui/span';
|
|||
|
||||
const ContextUrl = styled.div`
|
||||
padding: ${px(units.half)} ${px(unit)};
|
||||
background: ${theme.euiColorLightestShade};
|
||||
background: ${({ theme }) => theme.eui.euiColorLightestShade};
|
||||
border-radius: ${borderRadius};
|
||||
border: 1px solid ${theme.euiColorLightShade};
|
||||
border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
font-family: ${fontFamilyCode};
|
||||
font-size: ${fontSize};
|
||||
`;
|
||||
|
|
|
@ -8,7 +8,6 @@ import React from 'react';
|
|||
import styled from 'styled-components';
|
||||
|
||||
import { EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { isRumAgentName } from '../../../../../../../common/agent_name';
|
||||
import { px, unit, units } from '../../../../../../style/variables';
|
||||
|
@ -41,13 +40,13 @@ const Container = styled.div<IContainerStyleProps>`
|
|||
padding-bottom: ${px(units.plus)};
|
||||
margin-right: ${(props) => px(props.timelineMargins.right)};
|
||||
margin-left: ${(props) => px(props.timelineMargins.left)};
|
||||
border-top: 1px solid ${theme.euiColorLightShade};
|
||||
background-color: ${(props) =>
|
||||
props.isSelected ? theme.euiColorLightestShade : 'initial'};
|
||||
border-top: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
background-color: ${({ isSelected, theme }) =>
|
||||
isSelected ? theme.eui.euiColorLightestShade : 'initial'};
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: ${theme.euiColorLightestShade};
|
||||
background-color: ${({ theme }) => theme.eui.euiColorLightestShade};
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
import React from 'react';
|
||||
import cls from 'classnames';
|
||||
import styled from 'styled-components';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { px, unit } from '../../style/variables';
|
||||
|
||||
// TODO: replace this component with EUITab w/ a href prop
|
||||
|
@ -28,8 +27,8 @@ const Wrapper = styled.div<{ isSelected: boolean }>`
|
|||
a {
|
||||
display: inline-block;
|
||||
padding: ${px(unit * 0.75)} ${px(unit)};
|
||||
${({ isSelected }) =>
|
||||
!isSelected ? `color: ${theme.euiTextColor} !important;` : ''}
|
||||
${({ isSelected, theme }) =>
|
||||
!isSelected ? `color: ${theme.eui.euiTextColor} !important;` : ''}
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { isBoolean, isNumber, isObject } from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n';
|
||||
|
||||
const EmptyValue = styled.span`
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
text-align: left;
|
||||
`;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React from 'react';
|
||||
import { KeyValueTable } from '..';
|
||||
import { render } from '@testing-library/react';
|
||||
import { renderWithTheme } from '../../../../utils/testHelpers';
|
||||
|
||||
function getKeys(output: ReturnType<typeof render>) {
|
||||
const keys = output.getAllByTestId('dot-key');
|
||||
|
@ -31,7 +32,7 @@ describe('KeyValueTable', () => {
|
|||
{ key: 'nested.b.c', value: 'ccc' },
|
||||
{ key: 'nested.a', value: 'aaa' },
|
||||
];
|
||||
const output = render(<KeyValueTable keyValuePairs={data} />);
|
||||
const output = renderWithTheme(<KeyValueTable keyValuePairs={data} />);
|
||||
const rows = output.container.querySelectorAll('tr');
|
||||
expect(rows.length).toEqual(9);
|
||||
|
||||
|
|
|
@ -16,32 +16,31 @@ import {
|
|||
unit,
|
||||
} from '../../../../style/variables';
|
||||
import { tint } from 'polished';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
|
||||
function getIconColor(type) {
|
||||
function getIconColor(type, theme) {
|
||||
switch (type) {
|
||||
case 'field':
|
||||
return theme.euiColorVis7;
|
||||
return theme.eui.euiColorVis7;
|
||||
case 'value':
|
||||
return theme.euiColorVis0;
|
||||
return theme.eui.euiColorVis0;
|
||||
case 'operator':
|
||||
return theme.euiColorVis1;
|
||||
return theme.eui.euiColorVis1;
|
||||
case 'conjunction':
|
||||
return theme.euiColorVis3;
|
||||
return theme.eui.euiColorVis3;
|
||||
case 'recentSearch':
|
||||
return theme.euiColorMediumShade;
|
||||
return theme.eui.euiColorMediumShade;
|
||||
}
|
||||
}
|
||||
|
||||
const Description = styled.div`
|
||||
color: ${theme.euiColorDarkShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorDarkShade};
|
||||
|
||||
p {
|
||||
display: inline;
|
||||
|
||||
span {
|
||||
font-family: ${fontFamilyCode};
|
||||
color: ${theme.euiColorFullShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorFullShade};
|
||||
padding: 0 ${px(units.quarter)};
|
||||
display: inline-block;
|
||||
}
|
||||
|
@ -53,25 +52,25 @@ const ListItem = styled.li`
|
|||
height: ${px(units.double)};
|
||||
align-items: center;
|
||||
display: flex;
|
||||
background: ${(props) =>
|
||||
props.selected ? theme.euiColorLightestShade : 'initial'};
|
||||
background: ${({ selected, theme }) =>
|
||||
selected ? theme.eui.euiColorLightestShade : 'initial'};
|
||||
cursor: pointer;
|
||||
border-radius: ${px(units.quarter)};
|
||||
|
||||
${Description} {
|
||||
p span {
|
||||
background: ${(props) =>
|
||||
props.selected
|
||||
? theme.euiColorEmptyShade
|
||||
: theme.euiColorLightestShade};
|
||||
background: ${({ selected, theme }) =>
|
||||
selected
|
||||
? theme.eui.euiColorEmptyShade
|
||||
: theme.eui.euiColorLightestShade};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Icon = styled.div`
|
||||
flex: 0 0 ${px(units.double)};
|
||||
background: ${(props) => tint(0.1, getIconColor(props.type))};
|
||||
color: ${(props) => getIconColor(props.type)};
|
||||
background: ${({ type, theme }) => tint(0.1, getIconColor(type, theme))};
|
||||
color: ${({ type, theme }) => getIconColor(type, theme)};
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
|
@ -80,7 +79,7 @@ const Icon = styled.div`
|
|||
|
||||
const TextValue = styled.div`
|
||||
flex: 0 0 ${px(unit * 16)};
|
||||
color: ${theme.euiColorDarkestShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorDarkestShade};
|
||||
padding: 0 ${px(units.half)};
|
||||
`;
|
||||
|
||||
|
|
|
@ -11,16 +11,15 @@ import { isEmpty } from 'lodash';
|
|||
import Suggestion from './Suggestion';
|
||||
import { units, px, unit } from '../../../../style/variables';
|
||||
import { tint } from 'polished';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
|
||||
const List = styled.ul`
|
||||
width: 100%;
|
||||
border: 1px solid ${theme.euiColorLightShade};
|
||||
border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
border-radius: ${px(units.quarter)};
|
||||
box-shadow: 0px ${px(units.quarter)} ${px(units.double)}
|
||||
${tint(0.1, theme.euiColorFullShade)};
|
||||
${({ theme }) => tint(0.1, theme.eui.euiColorFullShade)};
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
background: ${({ theme }) => theme.eui.euiColorEmptyShade};
|
||||
z-index: 10;
|
||||
left: 0;
|
||||
max-height: ${px(unit * 20)};
|
||||
|
|
|
@ -18,7 +18,6 @@ import {
|
|||
EuiFlexGroup,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import styled from 'styled-components';
|
||||
import { FilterBadgeList } from './FilterBadgeList';
|
||||
import { unit, px } from '../../../../style/variables';
|
||||
|
@ -39,9 +38,9 @@ const SelectContainer = styled.div`
|
|||
`;
|
||||
|
||||
const Counter = styled.div`
|
||||
border-radius: ${theme.euiBorderRadius};
|
||||
background: ${theme.euiColorLightShade};
|
||||
padding: 0 ${theme.paddingSizes.xs};
|
||||
border-radius: ${({ theme }) => theme.eui.euiBorderRadius};
|
||||
background: ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
padding: 0 ${({ theme }) => theme.eui.paddingSizes.xs};
|
||||
`;
|
||||
|
||||
const ApplyButton = styled(EuiButton)`
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
import { CauseStacktrace } from './CauseStacktrace';
|
||||
import { mountWithTheme } from '../../../utils/testHelpers';
|
||||
|
||||
describe('CauseStacktrace', () => {
|
||||
describe('render', () => {
|
||||
|
@ -15,7 +16,7 @@ describe('CauseStacktrace', () => {
|
|||
const props = { id: 'testId', message: 'testMessage' };
|
||||
|
||||
expect(
|
||||
mount(<CauseStacktrace {...props} />).find('CausedBy')
|
||||
mountWithTheme(<CauseStacktrace {...props} />).find('CausedBy')
|
||||
).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
@ -28,7 +29,7 @@ describe('CauseStacktrace', () => {
|
|||
};
|
||||
|
||||
expect(
|
||||
mount(<CauseStacktrace {...props} />)
|
||||
mountWithTheme(<CauseStacktrace {...props} />)
|
||||
.find('EuiTitle span')
|
||||
.text()
|
||||
).toEqual('…');
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiAccordion, EuiTitle } from '@elastic/eui';
|
||||
import { px, unit } from '../../../style/variables';
|
||||
|
@ -15,18 +14,18 @@ import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackfram
|
|||
|
||||
// @ts-ignore Styled Components has trouble inferring the types of the default props here.
|
||||
const Accordion = styled(EuiAccordion)`
|
||||
border-top: ${theme.euiBorderThin};
|
||||
border-top: ${({ theme }) => theme.eui.euiBorderThin};
|
||||
`;
|
||||
|
||||
const CausedByContainer = styled('h5')`
|
||||
padding: ${theme.spacerSizes.s} 0;
|
||||
padding: ${({ theme }) => theme.eui.spacerSizes.s} 0;
|
||||
`;
|
||||
|
||||
const CausedByHeading = styled('span')`
|
||||
color: ${theme.textColors.subdued};
|
||||
color: ${({ theme }) => theme.eui.textColors.subdued};
|
||||
display: block;
|
||||
font-size: ${theme.euiFontSizeXS};
|
||||
font-weight: ${theme.euiFontWeightBold};
|
||||
font-size: ${({ theme }) => theme.eui.euiFontSizeXS};
|
||||
font-weight: ${({ theme }) => theme.eui.euiFontWeightBold};
|
||||
text-transform: uppercase;
|
||||
`;
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { size } from 'lodash';
|
||||
import { tint } from 'polished';
|
||||
import React from 'react';
|
||||
|
@ -41,7 +40,7 @@ const LineHighlight = styled.div<{ lineNumber: number }>`
|
|||
height: ${px(units.eighth * 9)};
|
||||
top: ${(props) => px(props.lineNumber * LINE_HEIGHT)};
|
||||
pointer-events: none;
|
||||
background-color: ${tint(0.1, theme.euiColorWarning)};
|
||||
background-color: ${({ theme }) => tint(0.1, theme.eui.euiColorWarning)};
|
||||
`;
|
||||
|
||||
const LineNumberContainer = styled.div<{ isLibraryFrame: boolean }>`
|
||||
|
@ -49,10 +48,10 @@ const LineNumberContainer = styled.div<{ isLibraryFrame: boolean }>`
|
|||
top: 0;
|
||||
left: 0;
|
||||
border-radius: ${borderRadius};
|
||||
background: ${(props) =>
|
||||
props.isLibraryFrame
|
||||
? theme.euiColorEmptyShade
|
||||
: theme.euiColorLightestShade};
|
||||
background: ${({ isLibraryFrame, theme }) =>
|
||||
isLibraryFrame
|
||||
? theme.eui.euiColorEmptyShade
|
||||
: theme.eui.euiColorLightestShade};
|
||||
`;
|
||||
|
||||
const LineNumber = styled.div<{ highlight: boolean }>`
|
||||
|
@ -60,12 +59,12 @@ const LineNumber = styled.div<{ highlight: boolean }>`
|
|||
min-width: ${px(units.eighth * 21)};
|
||||
padding-left: ${px(units.half)};
|
||||
padding-right: ${px(units.quarter)};
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
line-height: ${px(unit + units.eighth)};
|
||||
text-align: right;
|
||||
border-right: 1px solid ${theme.euiColorLightShade};
|
||||
background-color: ${(props) =>
|
||||
props.highlight ? tint(0.1, theme.euiColorWarning) : null};
|
||||
border-right: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
background-color: ${({ highlight, theme }) =>
|
||||
highlight ? tint(0.1, theme.eui.euiColorWarning) : null};
|
||||
|
||||
&:last-of-type {
|
||||
border-radius: 0 0 0 ${borderRadius};
|
||||
|
@ -76,7 +75,7 @@ const LineContainer = styled.div`
|
|||
overflow: auto;
|
||||
margin: 0 0 0 ${px(units.eighth * 21)};
|
||||
padding: 0;
|
||||
background-color: ${theme.euiColorEmptyShade};
|
||||
background-color: ${({ theme }) => theme.eui.euiColorEmptyShade};
|
||||
|
||||
&:last-of-type {
|
||||
border-radius: 0 0 ${borderRadius} 0;
|
||||
|
|
|
@ -4,25 +4,24 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React, { Fragment } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackframe';
|
||||
import { fontFamilyCode, fontSize, px, units } from '../../../style/variables';
|
||||
|
||||
const FileDetails = styled.div`
|
||||
color: ${theme.euiColorDarkShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorDarkShade};
|
||||
padding: ${px(units.half)} 0;
|
||||
font-family: ${fontFamilyCode};
|
||||
font-size: ${fontSize};
|
||||
`;
|
||||
|
||||
const LibraryFrameFileDetail = styled.span`
|
||||
color: ${theme.euiColorDarkShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorDarkShade};
|
||||
`;
|
||||
|
||||
const AppFrameFileDetail = styled.span`
|
||||
color: ${theme.euiColorFullShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorFullShade};
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiAccordion } from '@elastic/eui';
|
||||
|
@ -25,12 +24,12 @@ const ContextContainer = styled.div<{ isLibraryFrame: boolean }>`
|
|||
position: relative;
|
||||
font-family: ${fontFamilyCode};
|
||||
font-size: ${fontSize};
|
||||
border: 1px solid ${theme.euiColorLightShade};
|
||||
border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
border-radius: ${borderRadius};
|
||||
background: ${(props) =>
|
||||
props.isLibraryFrame
|
||||
? theme.euiColorEmptyShade
|
||||
: theme.euiColorLightestShade};
|
||||
background: ${({ isLibraryFrame, theme }) =>
|
||||
isLibraryFrame
|
||||
? theme.eui.euiColorEmptyShade
|
||||
: theme.eui.euiColorLightestShade};
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import styled from 'styled-components';
|
||||
import { EuiAccordion } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -15,7 +14,7 @@ import { KeyValueTable } from '../KeyValueTable';
|
|||
import { flattenObject } from '../../../utils/flattenObject';
|
||||
|
||||
const VariablesContainer = styled.div`
|
||||
background: ${theme.euiColorEmptyShade};
|
||||
background: ${({ theme }) => theme.eui.euiColorEmptyShade};
|
||||
border-radius: 0 0 ${borderRadius} ${borderRadius};
|
||||
padding: ${px(units.half)} ${px(unit)};
|
||||
`;
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mount, ReactWrapper, shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { ReactWrapper, shallow } from 'enzyme';
|
||||
import { IStackframe } from '../../../../../typings/es_schemas/raw/fields/stackframe';
|
||||
import { mountWithTheme } from '../../../../utils/testHelpers';
|
||||
import { Stackframe } from '../Stackframe';
|
||||
import stacktracesMock from './stacktraces.json';
|
||||
|
||||
|
@ -15,7 +16,9 @@ describe('Stackframe', () => {
|
|||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
const stackframe = stacktracesMock[0];
|
||||
wrapper = mount(<Stackframe id="test" stackframe={stackframe} />);
|
||||
wrapper = mountWithTheme(
|
||||
<Stackframe id="test" stackframe={stackframe} />
|
||||
);
|
||||
});
|
||||
|
||||
it('should render correctly', () => {
|
||||
|
@ -37,7 +40,9 @@ describe('Stackframe', () => {
|
|||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
const stackframe = { line: {} } as IStackframe;
|
||||
wrapper = mount(<Stackframe id="test" stackframe={stackframe} />);
|
||||
wrapper = mountWithTheme(
|
||||
<Stackframe id="test" stackframe={stackframe} />
|
||||
);
|
||||
});
|
||||
|
||||
it('should render only FrameHeading', () => {
|
||||
|
|
|
@ -383,8 +383,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"baseHash": -2021127760,
|
||||
"componentId": "sc-fzoLsD",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -401,7 +401,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"styledComponentId": "sc-fzoLsD",
|
||||
"target": "code",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -413,8 +413,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": -1923298833,
|
||||
"componentId": "sc-AxmLO",
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -439,7 +439,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-AxmLO",
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"target": "pre",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -608,8 +608,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"baseHash": -2021127760,
|
||||
"componentId": "sc-fzoLsD",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -626,7 +626,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"styledComponentId": "sc-fzoLsD",
|
||||
"target": "code",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -638,8 +638,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": -1923298833,
|
||||
"componentId": "sc-AxmLO",
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -664,7 +664,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-AxmLO",
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"target": "pre",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -834,8 +834,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"baseHash": -2021127760,
|
||||
"componentId": "sc-fzoLsD",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -852,7 +852,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"styledComponentId": "sc-fzoLsD",
|
||||
"target": "code",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -864,8 +864,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": -1923298833,
|
||||
"componentId": "sc-AxmLO",
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -890,7 +890,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-AxmLO",
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"target": "pre",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -1070,8 +1070,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"baseHash": -2021127760,
|
||||
"componentId": "sc-fzoLsD",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -1088,7 +1088,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"styledComponentId": "sc-fzoLsD",
|
||||
"target": "code",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -1100,8 +1100,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": -1923298833,
|
||||
"componentId": "sc-AxmLO",
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -1126,7 +1126,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-AxmLO",
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"target": "pre",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -1323,8 +1323,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"baseHash": -2021127760,
|
||||
"componentId": "sc-fzoLsD",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -1341,7 +1341,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"styledComponentId": "sc-fzoLsD",
|
||||
"target": "code",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -1353,8 +1353,8 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"baseHash": -1923298833,
|
||||
"componentId": "sc-AxmLO",
|
||||
"baseHash": 1280172402,
|
||||
"componentId": "sc-fzozJi",
|
||||
"isStatic": false,
|
||||
"rules": Array [
|
||||
"
|
||||
|
@ -1379,7 +1379,7 @@ exports[`Stackframe when stackframe has source lines should render correctly 1`]
|
|||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"shouldForwardProp": undefined,
|
||||
"styledComponentId": "sc-AxmLO",
|
||||
"styledComponentId": "sc-fzozJi",
|
||||
"target": "pre",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
|
@ -32,7 +31,7 @@ const TooltipFieldName = styled.span`
|
|||
const PropertyLabel = styled.div`
|
||||
margin-bottom: ${px(units.half)};
|
||||
font-size: ${fontSizes.small};
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
|
||||
span {
|
||||
cursor: help;
|
||||
|
|
|
@ -7,7 +7,7 @@ import React from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import styled from 'styled-components';
|
||||
import { EuiBadge } from '@elastic/eui';
|
||||
import euiThemeLight from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { useTheme } from '../../../hooks/useTheme';
|
||||
import { px } from '../../../../public/style/variables';
|
||||
import { units } from '../../../style/variables';
|
||||
|
||||
|
@ -19,12 +19,16 @@ const Badge = (styled(EuiBadge)`
|
|||
margin-top: ${px(units.eighth)};
|
||||
` as unknown) as typeof EuiBadge;
|
||||
|
||||
export const ErrorCountSummaryItemBadge = ({ count }: Props) => (
|
||||
<Badge color={euiThemeLight.euiColorDanger}>
|
||||
{i18n.translate('xpack.apm.transactionDetails.errorCount', {
|
||||
defaultMessage:
|
||||
'{errorCount, number} {errorCount, plural, one {Error} other {Errors}}',
|
||||
values: { errorCount: count },
|
||||
})}
|
||||
</Badge>
|
||||
);
|
||||
export const ErrorCountSummaryItemBadge = ({ count }: Props) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Badge color={theme.eui.euiColorDanger}>
|
||||
{i18n.translate('xpack.apm.transactionDetails.errorCount', {
|
||||
defaultMessage:
|
||||
'{errorCount, number} {errorCount, plural, one {Error} other {Errors}}',
|
||||
values: { errorCount: count },
|
||||
})}
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow, render } from 'enzyme';
|
||||
import { UserAgentSummaryItem } from './UserAgentSummaryItem';
|
||||
import { mountWithTheme } from '../../../utils/testHelpers';
|
||||
|
||||
describe('UserAgentSummaryItem', () => {
|
||||
describe('render', () => {
|
||||
|
@ -14,14 +14,14 @@ describe('UserAgentSummaryItem', () => {
|
|||
|
||||
it('renders', () => {
|
||||
expect(() =>
|
||||
shallow(<UserAgentSummaryItem {...props} />)
|
||||
mountWithTheme(<UserAgentSummaryItem {...props} />)
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
describe('with a version', () => {
|
||||
it('shows the version', () => {
|
||||
const p = { ...props, version: '1.0' };
|
||||
const wrapper = render(<UserAgentSummaryItem {...p} />);
|
||||
const wrapper = mountWithTheme(<UserAgentSummaryItem {...p} />);
|
||||
|
||||
expect(wrapper.text()).toContain('(1.0)');
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { UserAgent } from '../../../../typings/es_schemas/raw/fields/user_agent';
|
||||
|
@ -14,7 +13,7 @@ import { UserAgent } from '../../../../typings/es_schemas/raw/fields/user_agent'
|
|||
type UserAgentSummaryItemProps = UserAgent;
|
||||
|
||||
const Version = styled('span')`
|
||||
font-size: ${theme.euiFontSizeS};
|
||||
font-size: ${({ theme }) => theme.eui.euiFontSizeS};
|
||||
`;
|
||||
|
||||
export function UserAgentSummaryItem({
|
||||
|
|
|
@ -6,16 +6,19 @@
|
|||
|
||||
import React from 'react';
|
||||
import { ErrorCountSummaryItemBadge } from '../ErrorCountSummaryItemBadge';
|
||||
import { render } from '@testing-library/react';
|
||||
import { expectTextsInDocument } from '../../../../utils/testHelpers';
|
||||
import {
|
||||
expectTextsInDocument,
|
||||
renderWithTheme,
|
||||
} from '../../../../utils/testHelpers';
|
||||
|
||||
describe('ErrorCountSummaryItemBadge', () => {
|
||||
it('shows singular error message', () => {
|
||||
const component = render(<ErrorCountSummaryItemBadge count={1} />);
|
||||
const component = renderWithTheme(<ErrorCountSummaryItemBadge count={1} />);
|
||||
expectTextsInDocument(component, ['1 Error']);
|
||||
});
|
||||
|
||||
it('shows plural error message', () => {
|
||||
const component = render(<ErrorCountSummaryItemBadge count={2} />);
|
||||
const component = renderWithTheme(<ErrorCountSummaryItemBadge count={2} />);
|
||||
expectTextsInDocument(component, ['2 Errors']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
import React from 'react';
|
||||
import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { px, units } from '../../../../public/style/variables';
|
||||
import { Maybe } from '../../../../typings/common';
|
||||
|
||||
|
@ -14,12 +13,9 @@ interface Props {
|
|||
items: Array<Maybe<React.ReactElement>>;
|
||||
}
|
||||
|
||||
// TODO: Light/Dark theme (@see https://github.com/elastic/kibana/issues/44840)
|
||||
const theme = euiLightVars;
|
||||
|
||||
const Item = styled(EuiFlexItem)`
|
||||
flex-wrap: nowrap;
|
||||
border-right: 1px solid ${theme.euiColorLightShade};
|
||||
border-right: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
padding-right: ${px(units.half)};
|
||||
flex-flow: row nowrap;
|
||||
line-height: 1.5;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { VerticalGridLines } from 'react-vis';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import {
|
||||
EuiIcon,
|
||||
EuiToolTip,
|
||||
|
@ -14,6 +13,7 @@ import {
|
|||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import { Maybe } from '../../../../../typings/common';
|
||||
import { Annotation } from '../../../../../common/annotations';
|
||||
import { PlotValues, SharedPlot } from './plotUtils';
|
||||
|
@ -26,16 +26,15 @@ interface Props {
|
|||
overlay: Maybe<HTMLElement>;
|
||||
}
|
||||
|
||||
const style = {
|
||||
stroke: theme.euiColorSecondary,
|
||||
strokeDasharray: 'none',
|
||||
};
|
||||
|
||||
export function AnnotationsPlot(props: Props) {
|
||||
const { plotValues, annotations } = props;
|
||||
|
||||
export const AnnotationsPlot = ({ plotValues, annotations }: Props) => {
|
||||
const theme = useTheme();
|
||||
const tickValues = annotations.map((annotation) => annotation['@timestamp']);
|
||||
|
||||
const style = {
|
||||
stroke: theme.eui.euiColorSecondary,
|
||||
strokeDasharray: 'none',
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SharedPlot plotValues={plotValues}>
|
||||
|
@ -65,10 +64,10 @@ export function AnnotationsPlot(props: Props) {
|
|||
</EuiFlexGroup>
|
||||
}
|
||||
>
|
||||
<EuiIcon type="dot" color={theme.euiColorSecondary} />
|
||||
<EuiIcon type="dot" color={theme.eui.euiColorSecondary} />
|
||||
</EuiToolTip>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { Legend } from '../Legend';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import {
|
||||
unit,
|
||||
units,
|
||||
|
@ -15,7 +16,6 @@ import {
|
|||
px,
|
||||
truncate,
|
||||
} from '../../../../style/variables';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiIcon } from '@elastic/eui';
|
||||
|
||||
|
@ -36,7 +36,7 @@ const Container = styled.div`
|
|||
|
||||
const LegendContent = styled.span`
|
||||
white-space: nowrap;
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
|
@ -47,13 +47,13 @@ const TruncatedLabel = styled.span`
|
|||
|
||||
const SeriesValue = styled.span`
|
||||
margin-left: ${px(units.quarter)};
|
||||
color: ${theme.euiColorFullShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorFullShade};
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
const MoreSeriesContainer = styled.div`
|
||||
font-size: ${fontSizes.small};
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
`;
|
||||
|
||||
function MoreSeries({ hiddenSeriesCount }) {
|
||||
|
@ -80,6 +80,8 @@ export default function Legends({
|
|||
showAnnotations,
|
||||
onAnnotationsToggle,
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
|
||||
if (noHits && !hasAnnotations) {
|
||||
return null;
|
||||
}
|
||||
|
@ -90,6 +92,7 @@ export default function Legends({
|
|||
if (serie.hideLegend) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const text = (
|
||||
<LegendContent>
|
||||
{truncateLegends ? (
|
||||
|
@ -131,11 +134,11 @@ export default function Legends({
|
|||
}
|
||||
indicator={() => (
|
||||
<div style={{ marginRight: px(units.quarter) }}>
|
||||
<EuiIcon type="annotation" color={theme.euiColorSecondary} />
|
||||
<EuiIcon type="annotation" color={theme.eui.euiColorSecondary} />
|
||||
</div>
|
||||
)}
|
||||
disabled={!showAnnotations}
|
||||
color={theme.euiColorSecondary}
|
||||
color={theme.eui.euiColorSecondary}
|
||||
/>
|
||||
)}
|
||||
<MoreSeries hiddenSeriesCount={hiddenSeriesCount} />
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { toJson } from '../../../../../utils/testHelpers';
|
||||
import { toJson, mountWithTheme } from '../../../../../utils/testHelpers';
|
||||
import { InnerCustomPlot } from '../index';
|
||||
import responseWithData from './responseWithData.json';
|
||||
import VoronoiPlot from '../VoronoiPlot';
|
||||
|
@ -30,7 +29,7 @@ describe('when response has data', () => {
|
|||
onHover = jest.fn();
|
||||
onMouseLeave = jest.fn();
|
||||
onSelectionEnd = jest.fn();
|
||||
wrapper = mount(
|
||||
wrapper = mountWithTheme(
|
||||
<InnerCustomPlot
|
||||
series={series}
|
||||
onHover={onHover}
|
||||
|
@ -274,7 +273,7 @@ describe('when response has no data', () => {
|
|||
beforeEach(() => {
|
||||
const series = getEmptySeries(1451606400000, 1451610000000);
|
||||
|
||||
wrapper = mount(
|
||||
wrapper = mountWithTheme(
|
||||
<InnerCustomPlot
|
||||
annotations={annotations}
|
||||
series={series}
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import d3 from 'd3';
|
||||
import { HistogramInner } from '../index';
|
||||
|
@ -14,7 +13,7 @@ import {
|
|||
getDurationFormatter,
|
||||
asInteger,
|
||||
} from '../../../../../utils/formatters';
|
||||
import { toJson } from '../../../../../utils/testHelpers';
|
||||
import { toJson, mountWithTheme } from '../../../../../utils/testHelpers';
|
||||
import { getFormattedBuckets } from '../../../../app/TransactionDetails/Distribution/index';
|
||||
|
||||
describe('Histogram', () => {
|
||||
|
@ -26,7 +25,7 @@ describe('Histogram', () => {
|
|||
const xMax = d3.max(buckets, (d) => d.x);
|
||||
const timeFormatter = getDurationFormatter(xMax);
|
||||
|
||||
wrapper = mount(
|
||||
wrapper = mountWithTheme(
|
||||
<HistogramInner
|
||||
buckets={buckets}
|
||||
bucketSize={response.bucketSize}
|
||||
|
@ -46,10 +45,6 @@ describe('Histogram', () => {
|
|||
});
|
||||
|
||||
describe('Initially', () => {
|
||||
it('should have default state', () => {
|
||||
expect(wrapper.state()).toEqual({ hoveredBucket: {} });
|
||||
});
|
||||
|
||||
it('should have default markup', () => {
|
||||
expect(toJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
@ -86,23 +81,6 @@ describe('Histogram', () => {
|
|||
expect(tooltips.prop('y')).toEqual(27.5);
|
||||
});
|
||||
|
||||
it('should update state with "hoveredBucket"', () => {
|
||||
expect(wrapper.state()).toEqual({
|
||||
hoveredBucket: {
|
||||
samples: [
|
||||
{
|
||||
transactionId: '99c50a5b-44b4-4289-a3d1-a2815d128192',
|
||||
},
|
||||
],
|
||||
style: { cursor: 'pointer' },
|
||||
xCenter: 869010,
|
||||
x0: 811076,
|
||||
x: 926944,
|
||||
y: 49,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should have correct markup for tooltip', () => {
|
||||
const tooltips = wrapper.find('Tooltip');
|
||||
expect(toJson(tooltips)).toMatchSnapshot();
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import { fontSizes, px, units } from '../../../../style/variables';
|
||||
|
||||
export enum Shape {
|
||||
|
@ -20,11 +20,12 @@ interface ContainerProps {
|
|||
clickable: boolean;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
||||
const Container = styled.div<ContainerProps>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: ${(props) => props.fontSize};
|
||||
color: ${theme.euiColorDarkShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorDarkShade};
|
||||
cursor: ${(props) => (props.clickable ? 'pointer' : 'initial')};
|
||||
opacity: ${(props) => (props.disabled ? 0.4 : 1)};
|
||||
user-select: none;
|
||||
|
@ -36,6 +37,7 @@ interface IndicatorProps {
|
|||
shape: Shape;
|
||||
withMargin: boolean;
|
||||
}
|
||||
|
||||
export const Indicator = styled.span<IndicatorProps>`
|
||||
width: ${(props) => px(props.radius)};
|
||||
height: ${(props) => px(props.radius)};
|
||||
|
@ -61,7 +63,7 @@ interface Props {
|
|||
export const Legend: React.FC<Props> = ({
|
||||
onClick,
|
||||
text,
|
||||
color = theme.euiColorVis1,
|
||||
color,
|
||||
fontSize = fontSizes.small,
|
||||
radius = units.minus - 1,
|
||||
disabled = false,
|
||||
|
@ -70,6 +72,9 @@ export const Legend: React.FC<Props> = ({
|
|||
indicator,
|
||||
...rest
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const indicatorColor = color || theme.eui.euiColorVis1;
|
||||
|
||||
return (
|
||||
<Container
|
||||
onClick={onClick}
|
||||
|
@ -82,7 +87,7 @@ export const Legend: React.FC<Props> = ({
|
|||
indicator()
|
||||
) : (
|
||||
<Indicator
|
||||
color={color}
|
||||
color={indicatorColor}
|
||||
radius={radius}
|
||||
shape={shape}
|
||||
withMargin={!!text}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { shallow } from 'enzyme';
|
|||
import React from 'react';
|
||||
import { AgentMarker } from './AgentMarker';
|
||||
import { AgentMark } from '../../../../app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks';
|
||||
import { EuiThemeProvider } from '../../../../../../../observability/public';
|
||||
|
||||
describe('AgentMarker', () => {
|
||||
const mark = {
|
||||
|
@ -16,8 +17,14 @@ describe('AgentMarker', () => {
|
|||
type: 'agentMark',
|
||||
verticalLine: true,
|
||||
} as AgentMark;
|
||||
|
||||
it('renders', () => {
|
||||
const component = shallow(<AgentMarker mark={mark} />);
|
||||
const component = shallow(
|
||||
<EuiThemeProvider>
|
||||
<AgentMarker mark={mark} />
|
||||
</EuiThemeProvider>
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React from 'react';
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import { useTheme } from '../../../../../hooks/useTheme';
|
||||
import { px, units } from '../../../../../style/variables';
|
||||
import { asDuration } from '../../../../../utils/formatters';
|
||||
import { Legend } from '../../Legend';
|
||||
import { AgentMark } from '../../../../app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks';
|
||||
|
||||
const NameContainer = styled.div`
|
||||
border-bottom: 1px solid ${theme.euiColorMediumShade};
|
||||
border-bottom: 1px solid ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
padding-bottom: ${px(units.half)};
|
||||
`;
|
||||
|
||||
const TimeContainer = styled.div`
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
padding-top: ${px(units.half)};
|
||||
`;
|
||||
|
||||
|
@ -28,6 +28,8 @@ interface Props {
|
|||
}
|
||||
|
||||
export const AgentMarker: React.FC<Props> = ({ mark }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiToolTip
|
||||
|
@ -40,7 +42,7 @@ export const AgentMarker: React.FC<Props> = ({ mark }) => {
|
|||
</div>
|
||||
}
|
||||
>
|
||||
<Legend clickable color={theme.euiColorMediumShade} />
|
||||
<Legend clickable color={theme.eui.euiColorMediumShade} />
|
||||
</EuiToolTip>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
import React from 'react';
|
||||
import { ErrorMarker } from './ErrorMarker';
|
||||
import { ErrorMark } from '../../../../app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import { act } from '@testing-library/react-hooks';
|
||||
import { expectTextsInDocument } from '../../../../../utils/testHelpers';
|
||||
import {
|
||||
expectTextsInDocument,
|
||||
renderWithTheme,
|
||||
} from '../../../../../utils/testHelpers';
|
||||
|
||||
describe('ErrorMarker', () => {
|
||||
const mark = ({
|
||||
|
@ -33,7 +36,7 @@ describe('ErrorMarker', () => {
|
|||
} as unknown) as ErrorMark;
|
||||
|
||||
function openPopover(errorMark: ErrorMark) {
|
||||
const component = render(<ErrorMarker mark={errorMark} />);
|
||||
const component = renderWithTheme(<ErrorMarker mark={errorMark} />);
|
||||
act(() => {
|
||||
fireEvent.click(component.getByTestId('popover'));
|
||||
});
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiPopover, EuiText } from '@elastic/eui';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React, { useState } from 'react';
|
||||
import { EuiPopover, EuiText } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import { useTheme } from '../../../../../hooks/useTheme';
|
||||
import {
|
||||
TRACE_ID,
|
||||
TRANSACTION_ID,
|
||||
|
@ -54,6 +54,7 @@ function truncateMessage(errorMessage?: string) {
|
|||
}
|
||||
|
||||
export const ErrorMarker: React.FC<Props> = ({ mark }) => {
|
||||
const theme = useTheme();
|
||||
const { urlParams } = useUrlParams();
|
||||
const [isPopoverOpen, showPopover] = useState(false);
|
||||
|
||||
|
@ -63,7 +64,7 @@ export const ErrorMarker: React.FC<Props> = ({ mark }) => {
|
|||
<Button
|
||||
data-test-subj="popover"
|
||||
clickable
|
||||
color={theme.euiColorDanger}
|
||||
color={theme.eui.euiColorDanger}
|
||||
shape={Shape.square}
|
||||
onClick={togglePopover}
|
||||
/>
|
||||
|
|
|
@ -1,26 +1,18 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AgentMarker renders 1`] = `
|
||||
<Fragment>
|
||||
<EuiToolTip
|
||||
content={
|
||||
<div>
|
||||
<ForwardRef(styled.div)>
|
||||
agent
|
||||
</ForwardRef(styled.div)>
|
||||
<ForwardRef(styled.div)>
|
||||
1,000 μs
|
||||
</ForwardRef(styled.div)>
|
||||
</div>
|
||||
<ThemeProvider
|
||||
theme={[Function]}
|
||||
>
|
||||
<AgentMarker
|
||||
mark={
|
||||
Object {
|
||||
"id": "agent",
|
||||
"offset": 1000,
|
||||
"type": "agentMark",
|
||||
"verticalLine": true,
|
||||
}
|
||||
}
|
||||
delay="regular"
|
||||
id="agent"
|
||||
position="top"
|
||||
>
|
||||
<Legend
|
||||
clickable={true}
|
||||
color="#98a2b3"
|
||||
/>
|
||||
</EuiToolTip>
|
||||
</Fragment>
|
||||
/>
|
||||
</ThemeProvider>
|
||||
`;
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { StickyContainer } from 'react-sticky';
|
||||
import { mockMoment, toJson } from '../../../../utils/testHelpers';
|
||||
import {
|
||||
mountWithTheme,
|
||||
mockMoment,
|
||||
toJson,
|
||||
} from '../../../../utils/testHelpers';
|
||||
import { Timeline } from '.';
|
||||
|
||||
describe('Timeline', () => {
|
||||
|
@ -50,7 +53,7 @@ describe('Timeline', () => {
|
|||
],
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
const wrapper = mountWithTheme(
|
||||
<StickyContainer>
|
||||
<Timeline {...props} />
|
||||
</StickyContainer>
|
||||
|
@ -74,7 +77,7 @@ describe('Timeline', () => {
|
|||
};
|
||||
|
||||
const mountTimeline = () =>
|
||||
mount(
|
||||
mountWithTheme(
|
||||
<StickyContainer>
|
||||
<Timeline {...props} />
|
||||
</StickyContainer>
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { inRange } from 'lodash';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { inRange } from 'lodash';
|
||||
import { Sticky } from 'react-sticky';
|
||||
import { XAxis, XYPlot } from 'react-vis';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import { px } from '../../../../style/variables';
|
||||
import { getDurationFormatter } from '../../../../utils/formatters';
|
||||
import { Mark } from './';
|
||||
|
@ -42,11 +42,12 @@ interface TimelineAxisProps {
|
|||
topTraceDuration: number;
|
||||
}
|
||||
|
||||
export function TimelineAxis({
|
||||
export const TimelineAxis = ({
|
||||
plotValues,
|
||||
marks = [],
|
||||
topTraceDuration,
|
||||
}: TimelineAxisProps) {
|
||||
}: TimelineAxisProps) => {
|
||||
const theme = useTheme();
|
||||
const { margins, tickValues, width, xDomain, xMax, xScale } = plotValues;
|
||||
const tickFormatter = getDurationFormatter(xMax);
|
||||
const xAxisTickValues = getXAxisTickValues(tickValues, topTraceDuration);
|
||||
|
@ -59,7 +60,7 @@ export function TimelineAxis({
|
|||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
borderBottom: `1px solid ${theme.euiColorMediumShade}`,
|
||||
borderBottom: `1px solid ${theme.eui.euiColorMediumShade}`,
|
||||
height: px(margins.top),
|
||||
zIndex: 2,
|
||||
width: '100%',
|
||||
|
@ -85,7 +86,7 @@ export function TimelineAxis({
|
|||
tickFormat={(time?: number) => tickFormatter(time).formatted}
|
||||
tickPadding={20}
|
||||
style={{
|
||||
text: { fill: theme.euiColorDarkShade },
|
||||
text: { fill: theme.eui.euiColorDarkShade },
|
||||
}}
|
||||
/>
|
||||
|
||||
|
@ -106,4 +107,4 @@ export function TimelineAxis({
|
|||
}}
|
||||
</Sticky>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import React, { PureComponent } from 'react';
|
||||
import React from 'react';
|
||||
import { VerticalGridLines, XYPlot } from 'react-vis';
|
||||
import { useTheme } from '../../../../hooks/useTheme';
|
||||
import { Mark } from '../../../app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks';
|
||||
import { PlotValues } from './plotUtils';
|
||||
|
||||
|
@ -16,54 +16,51 @@ interface VerticalLinesProps {
|
|||
topTraceDuration: number;
|
||||
}
|
||||
|
||||
export class VerticalLines extends PureComponent<VerticalLinesProps> {
|
||||
render() {
|
||||
const { topTraceDuration, marks = [] } = this.props;
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
margins,
|
||||
xDomain,
|
||||
tickValues,
|
||||
} = this.props.plotValues;
|
||||
export const VerticalLines = ({
|
||||
topTraceDuration,
|
||||
plotValues,
|
||||
marks = [],
|
||||
}: VerticalLinesProps) => {
|
||||
const { width, height, margins, xDomain, tickValues } = plotValues;
|
||||
|
||||
const markTimes = marks
|
||||
.filter((mark) => mark.verticalLine)
|
||||
.map(({ offset }) => offset);
|
||||
const markTimes = marks
|
||||
.filter((mark) => mark.verticalLine)
|
||||
.map(({ offset }) => offset);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
>
|
||||
<XYPlot
|
||||
dontCheckIfEmpty
|
||||
width={width}
|
||||
height={height + margins.top}
|
||||
margin={margins}
|
||||
xDomain={xDomain}
|
||||
>
|
||||
<XYPlot
|
||||
dontCheckIfEmpty
|
||||
width={width}
|
||||
height={height + margins.top}
|
||||
margin={margins}
|
||||
xDomain={xDomain}
|
||||
>
|
||||
<VerticalGridLines
|
||||
tickValues={tickValues}
|
||||
style={{ stroke: theme.euiColorLightestShade }}
|
||||
/>
|
||||
<VerticalGridLines
|
||||
tickValues={tickValues}
|
||||
style={{ stroke: theme.eui.euiColorLightestShade }}
|
||||
/>
|
||||
|
||||
<VerticalGridLines
|
||||
tickValues={markTimes}
|
||||
style={{ stroke: theme.euiColorMediumShade }}
|
||||
/>
|
||||
<VerticalGridLines
|
||||
tickValues={markTimes}
|
||||
style={{ stroke: theme.eui.euiColorMediumShade }}
|
||||
/>
|
||||
|
||||
{topTraceDuration > 0 && (
|
||||
<VerticalGridLines
|
||||
tickValues={[topTraceDuration]}
|
||||
style={{ stroke: theme.euiColorMediumShade }}
|
||||
/>
|
||||
)}
|
||||
</XYPlot>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
{topTraceDuration > 0 && (
|
||||
<VerticalGridLines
|
||||
tickValues={[topTraceDuration]}
|
||||
style={{ stroke: theme.eui.euiColorMediumShade }}
|
||||
/>
|
||||
)}
|
||||
</XYPlot>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -18,25 +18,24 @@ import {
|
|||
fontSizes,
|
||||
} from '../../../../style/variables';
|
||||
import { Legend } from '../Legend';
|
||||
import theme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { asAbsoluteDateTime } from '../../../../utils/formatters';
|
||||
|
||||
const TooltipElm = styled.div`
|
||||
margin: 0 ${px(unit)};
|
||||
transform: translateY(-50%);
|
||||
border: 1px solid ${theme.euiColorLightShade};
|
||||
background: ${theme.euiColorEmptyShade};
|
||||
border: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
background: ${({ theme }) => theme.eui.euiColorEmptyShade};
|
||||
border-radius: ${borderRadius};
|
||||
font-size: ${fontSize};
|
||||
color: ${theme.euiColorFullShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorFullShade};
|
||||
`;
|
||||
|
||||
const Header = styled.div`
|
||||
background: ${theme.euiColorLightestShade};
|
||||
border-bottom: 1px solid ${theme.euiColorLightShade};
|
||||
background: ${({ theme }) => theme.eui.euiColorLightestShade};
|
||||
border-bottom: 1px solid ${({ theme }) => theme.eui.euiColorLightShade};
|
||||
border-radius: ${borderRadius} ${borderRadius} 0 0;
|
||||
padding: ${px(units.half)};
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
`;
|
||||
|
||||
const Content = styled.div`
|
||||
|
@ -46,7 +45,7 @@ const Content = styled.div`
|
|||
`;
|
||||
|
||||
const Footer = styled.div`
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
margin: ${px(units.half)};
|
||||
font-size: ${fontSizes.small};
|
||||
`;
|
||||
|
@ -59,13 +58,13 @@ const LegendContainer = styled.div`
|
|||
`;
|
||||
|
||||
const LegendGray = styled(Legend)`
|
||||
color: ${theme.euiColorMediumShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorMediumShade};
|
||||
padding-bottom: 0;
|
||||
padding-right: ${px(units.half)};
|
||||
`;
|
||||
|
||||
const Value = styled.div`
|
||||
color: ${theme.euiColorDarkShade};
|
||||
color: ${({ theme }) => theme.eui.euiColorDarkShade};
|
||||
font-size: ${fontSize};
|
||||
`;
|
||||
|
||||
|
|
|
@ -13,8 +13,9 @@ import React, {
|
|||
} from 'react';
|
||||
import { Map, NavigationControl, Popup } from 'mapbox-gl';
|
||||
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { shade, tint } from 'polished';
|
||||
import { EuiTheme } from '../../../../../../../observability/public';
|
||||
import { useTheme } from '../../../../../hooks/useTheme';
|
||||
import { ChoroplethToolTip } from './ChoroplethToolTip';
|
||||
|
||||
interface ChoroplethItem {
|
||||
|
@ -47,8 +48,8 @@ const MAPBOX_STYLE =
|
|||
const GEOJSON_SOURCE =
|
||||
'https://vector.maps.elastic.co/files/world_countries_v1.geo.json?elastic_tile_service_tos=agree&my_app_name=ems-landing&my_app_version=7.2.0';
|
||||
|
||||
export function getProgressionColor(scale: number) {
|
||||
const baseColor = euiLightVars.euiColorPrimary;
|
||||
export function getProgressionColor(scale: number, theme: EuiTheme) {
|
||||
const baseColor = theme.eui.euiColorPrimary;
|
||||
const adjustedScale = 0.75 * scale + 0.05; // prevents pure black & white as min/max colors.
|
||||
if (adjustedScale < 0.5) {
|
||||
return tint(adjustedScale * 2, baseColor);
|
||||
|
@ -66,8 +67,8 @@ const getMax = (items: ChoroplethItem[]) =>
|
|||
Math.max(...items.map((item) => item.value));
|
||||
|
||||
export const ChoroplethMap: React.FC<Props> = (props) => {
|
||||
const theme = useTheme();
|
||||
const { items } = props;
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [map, setMap] = useState<Map | null>(null);
|
||||
const popupRef = useRef<Popup | null>(null);
|
||||
|
@ -215,7 +216,7 @@ export const ChoroplethMap: React.FC<Props> = (props) => {
|
|||
|
||||
const stops = items.map(({ key, value }) => [
|
||||
key,
|
||||
getProgressionColor(getValueScale(value)),
|
||||
getProgressionColor(getValueScale(value), theme),
|
||||
]);
|
||||
|
||||
const fillColor: mapboxgl.FillPaint['fill-color'] = {
|
||||
|
@ -238,7 +239,7 @@ export const ChoroplethMap: React.FC<Props> = (props) => {
|
|||
},
|
||||
symbolLayer ? symbolLayer.id : undefined
|
||||
);
|
||||
}, [map, items, getValueScale]);
|
||||
}, [map, items, theme, getValueScale]);
|
||||
|
||||
// side effect to only render the Popup when hovering a region with a matching item
|
||||
useEffect(() => {
|
||||
|
|
14
x-pack/plugins/apm/public/hooks/useTheme.tsx
Normal file
14
x-pack/plugins/apm/public/hooks/useTheme.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 { useContext } from 'react';
|
||||
import { ThemeContext } from 'styled-components';
|
||||
import { EuiTheme } from '../../../observability/public';
|
||||
|
||||
export function useTheme(): EuiTheme {
|
||||
const theme = useContext(ThemeContext);
|
||||
return theme;
|
||||
}
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
/* global jest */
|
||||
|
||||
import { ReactWrapper } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { ReactWrapper, mount, MountRendererProps } from 'enzyme';
|
||||
import enzymeToJson from 'enzyme-to-json';
|
||||
import { Location } from 'history';
|
||||
import moment from 'moment';
|
||||
import { Moment } from 'moment-timezone';
|
||||
import React from 'react';
|
||||
import { render, waitForElement } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
@ -19,6 +19,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|||
import { APMConfig } from '../../server';
|
||||
import { LocationProvider } from '../context/LocationContext';
|
||||
import { PromiseReturnType } from '../../typings/common';
|
||||
import { EuiThemeProvider } from '../../../observability/public';
|
||||
import {
|
||||
ESFilter,
|
||||
ESSearchResponse,
|
||||
|
@ -181,3 +182,27 @@ export async function inspectSearchParams(
|
|||
}
|
||||
|
||||
export type SearchParamsMock = PromiseReturnType<typeof inspectSearchParams>;
|
||||
|
||||
export function renderWithTheme(
|
||||
component: React.ReactNode,
|
||||
params?: any,
|
||||
{ darkMode = false } = {}
|
||||
) {
|
||||
return render(
|
||||
<EuiThemeProvider darkMode={darkMode}>{component}</EuiThemeProvider>,
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
export function mountWithTheme(
|
||||
tree: React.ReactElement<any>,
|
||||
{ darkMode = false } = {}
|
||||
) {
|
||||
const WrappingThemeProvider = (props: any) => (
|
||||
<EuiThemeProvider darkMode={darkMode}>{props.children}</EuiThemeProvider>
|
||||
);
|
||||
|
||||
return mount(tree, {
|
||||
wrappingComponent: WrappingThemeProvider,
|
||||
} as MountRendererProps);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue