TraceView: Refactor theming to use Grafana theme directly (#43856)

* Use grafana theme and utils

* Use grafana colors

* Fix tests

* Use useStyles2
pull/43902/head
Andrej Ocenas 4 years ago committed by GitHub
parent 44cca3e4c1
commit 8b45eb1161
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 175
      packages/jaeger-ui-components/src/Theme.tsx
  2. 4
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/CanvasSpanGraph.test.js
  3. 10
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/CanvasSpanGraph.tsx
  4. 9
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/GraphTicks.tsx
  5. 9
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/Scrubber.tsx
  6. 11
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/TickLabels.tsx
  7. 27
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/ViewingLayer.test.js
  8. 10
      packages/jaeger-ui-components/src/TracePageHeader/SpanGraph/ViewingLayer.tsx
  9. 12
      packages/jaeger-ui-components/src/TracePageHeader/TracePageHeader.tsx
  10. 8
      packages/jaeger-ui-components/src/TracePageHeader/TracePageSearchBar.tsx
  11. 6
      packages/jaeger-ui-components/src/TraceTimelineViewer/ReferencesButton.tsx
  12. 12
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanBar.tsx
  13. 11
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanBarRow.tsx
  14. 12
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianKeyValues.tsx
  15. 10
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianLogs.tsx
  16. 9
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianReferences.tsx
  17. 13
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianText.tsx
  18. 4
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/KeyValuesTable.test.js
  19. 13
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/KeyValuesTable.tsx
  20. 9
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/TextList.tsx
  21. 12
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/index.tsx
  22. 9
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetailRow.test.js
  23. 10
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetailRow.tsx
  24. 7
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanTreeOffset.test.js
  25. 11
      packages/jaeger-ui-components/src/TraceTimelineViewer/SpanTreeOffset.tsx
  26. 10
      packages/jaeger-ui-components/src/TraceTimelineViewer/Ticks.tsx
  27. 9
      packages/jaeger-ui-components/src/TraceTimelineViewer/TimelineHeaderRow/TimelineCollapser.tsx
  28. 4
      packages/jaeger-ui-components/src/TraceTimelineViewer/TimelineHeaderRow/TimelineColumnResizer.tsx
  29. 10
      packages/jaeger-ui-components/src/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
  30. 5
      packages/jaeger-ui-components/src/TraceTimelineViewer/TimelineHeaderRow/TimelineViewingLayer.tsx
  31. 8
      packages/jaeger-ui-components/src/TraceTimelineViewer/TimelineRow.tsx
  32. 1
      packages/jaeger-ui-components/src/TraceTimelineViewer/VirtualizedTraceView.test.js
  33. 11
      packages/jaeger-ui-components/src/TraceTimelineViewer/VirtualizedTraceView.tsx
  34. 4
      packages/jaeger-ui-components/src/TraceTimelineViewer/index.test.js
  35. 10
      packages/jaeger-ui-components/src/TraceTimelineViewer/index.tsx
  36. 10
      packages/jaeger-ui-components/src/common/BreakableText.tsx
  37. 4
      packages/jaeger-ui-components/src/common/CopyIcon.tsx
  38. 11
      packages/jaeger-ui-components/src/common/LabeledList.tsx
  39. 8
      packages/jaeger-ui-components/src/common/LoadingIndicator.tsx
  40. 9
      packages/jaeger-ui-components/src/common/NewWindowIcon.tsx
  41. 12
      packages/jaeger-ui-components/src/common/TraceName.tsx
  42. 14
      packages/jaeger-ui-components/src/utils/color-generator.test.js
  43. 11
      packages/jaeger-ui-components/src/utils/color-generator.tsx
  44. 139
      public/app/features/explore/TraceView/TraceView.tsx

@ -12,161 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import React, { useContext } from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import memoizeOne from 'memoize-one';
import tinycolor from 'tinycolor2';
const COLORS_HEX = [
'#17B8BE',
'#F8DCA1',
'#B7885E',
'#FFCB99',
'#F89570',
'#829AE3',
'#E79FD5',
'#1E96BE',
'#89DAC1',
'#B3AD9E',
'#12939A',
'#DDB27C',
'#88572C',
'#FF9833',
'#EF5D28',
'#162A65',
'#DA70BF',
'#125C77',
'#4DC19C',
'#776E57',
];
const COLORS_HEX_DARK = [
'#17B8BE',
'#F8DCA1',
'#B7885E',
'#FFCB99',
'#F89570',
'#829AE3',
'#E79FD5',
'#1E96BE',
'#89DAC1',
'#B3AD9E',
'#12939A',
'#DDB27C',
'#88572C',
'#FF9833',
'#EF5D28',
'#DA70BF',
'#4DC19C',
'#776E57',
];
export type ThemeOptions = Partial<Theme>;
export enum ThemeType {
Dark,
Light,
}
export type Theme = {
type: ThemeType;
servicesColorPalette: string[];
borderStyle: string;
components?: {
TraceName?: {
fontSize?: number | string;
};
};
};
export const defaultTheme: Theme = {
type: ThemeType.Light,
borderStyle: '1px solid #bbb',
servicesColorPalette: COLORS_HEX,
};
export function isLight(theme?: Theme | ThemeOptions) {
// Light theme is default type not set which only happens if called for ThemeOptions.
return theme && theme.type ? theme.type === ThemeType.Light : false;
}
const ThemeContext = React.createContext<ThemeOptions | undefined>(undefined);
ThemeContext.displayName = 'ThemeContext';
export const ThemeProvider = ThemeContext.Provider;
type ThemeConsumerProps = {
children: (theme: Theme) => React.ReactNode;
};
export function ThemeConsumer(props: ThemeConsumerProps) {
return (
<ThemeContext.Consumer>
{(value: ThemeOptions | undefined) => {
const theme = memoizedThemeMerge(value);
return props.children(theme);
}}
</ThemeContext.Consumer>
);
}
const memoizedThemeMerge = memoizeOne((value?: ThemeOptions) => {
const darkOverrides: Partial<Theme> = {};
if (!isLight(value)) {
darkOverrides.servicesColorPalette = COLORS_HEX_DARK;
}
return value
? {
...defaultTheme,
...darkOverrides,
...value,
}
: defaultTheme;
});
type WrappedWithThemeComponent<Props> = React.ComponentType<Omit<Props, 'theme'>> & {
wrapped: React.ComponentType<Props>;
};
export const withTheme = <Props extends { theme: Theme }, Statics extends {} = {}>(
Component: React.ComponentType<Props>
): WrappedWithThemeComponent<Props> => {
let WithTheme: React.ComponentType<Omit<Props, 'theme'>> = (props) => {
return (
<ThemeConsumer>
{(theme: Theme) => {
return (
<Component
{...({
...props,
theme,
} as Props & { theme: Theme })}
/>
);
}}
</ThemeConsumer>
);
};
WithTheme.displayName = `WithTheme(${Component.displayName})`;
WithTheme = hoistNonReactStatics<React.ComponentType<Omit<Props, 'theme'>>, React.ComponentType<Props>>(
WithTheme,
Component
);
(WithTheme as WrappedWithThemeComponent<Props>).wrapped = Component;
return WithTheme as WrappedWithThemeComponent<Props>;
};
export function useTheme(): Theme {
const theme = useContext(ThemeContext);
return {
...defaultTheme,
...theme,
};
}
export const createStyle = <Fn extends (this: any, ...newArgs: any[]) => ReturnType<Fn>>(fn: Fn) => {
return memoizeOne(fn);
};
import { GrafanaTheme2 } from '@grafana/data';
/**
* Tries to get a dark variant color. Either by simply inverting the luminosity and darkening or lightening the color
@ -176,8 +23,8 @@ export const createStyle = <Fn extends (this: any, ...newArgs: any[]) => ReturnT
* @param hex
* @param base
*/
export function autoColor(theme: Theme, hex: string, base?: string) {
if (isLight(theme)) {
export function autoColor(theme: GrafanaTheme2, hex: string, base?: string) {
if (theme.isLight) {
return hex;
} else {
if (base) {
@ -204,19 +51,3 @@ export function autoColor(theme: Theme, hex: string, base?: string) {
return newColor.isLight() ? newColor.darken(5).toHex8String() : newColor.lighten(5).toHex8String();
}
}
/**
* With theme overrides you can use both number or string (for things like rem units) so this makes sure we convert
* the value accordingly or use fallback if not set
*/
export function safeSize(size: number | string | undefined, fallback: string): string {
if (!size) {
return fallback;
}
if (typeof size === 'string') {
return size;
} else {
return `${size}px`;
}
}

@ -14,14 +14,14 @@
import React from 'react';
import { shallow } from 'enzyme';
import { createTheme } from '@grafana/data';
import { UnthemedCanvasSpanGraph } from './CanvasSpanGraph';
import { defaultTheme } from '../../Theme';
describe('<CanvasSpanGraph>', () => {
it('renders without exploding', () => {
const items = [{ valueWidth: 1, valueOffset: 1, serviceName: 'service-name-0' }];
const wrapper = shallow(<UnthemedCanvasSpanGraph items={[]} valueWidth={4000} theme={defaultTheme} />);
const wrapper = shallow(<UnthemedCanvasSpanGraph items={[]} valueWidth={4000} theme={createTheme()} />);
expect(wrapper).toBeDefined();
wrapper.instance()._setCanvasRef({
getContext: () => ({

@ -19,9 +19,11 @@ import renderIntoCanvas from './render-into-canvas';
import { getRgbColorByKey } from '../../utils/color-generator';
import { TNil } from '../../types';
import { autoColor, createStyle, Theme, withTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { withTheme2, stylesFactory } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
const getStyles = createStyle((theme: Theme) => {
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
CanvasSpanGraph: css`
label: CanvasSpanGraph;
@ -36,7 +38,7 @@ const getStyles = createStyle((theme: Theme) => {
type CanvasSpanGraphProps = {
items: Array<{ valueWidth: number; valueOffset: number; serviceName: string }>;
valueWidth: number;
theme: Theme;
theme: GrafanaTheme2;
};
export class UnthemedCanvasSpanGraph extends React.PureComponent<CanvasSpanGraphProps> {
@ -73,4 +75,4 @@ export class UnthemedCanvasSpanGraph extends React.PureComponent<CanvasSpanGraph
}
}
export default withTheme(UnthemedCanvasSpanGraph);
export default withTheme2(UnthemedCanvasSpanGraph);

@ -14,9 +14,9 @@
import React from 'react';
import { css } from '@emotion/css';
import { createStyle } from '../../Theme';
import { useStyles2 } from '@grafana/ui';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
GraphTick: css`
label: GraphTick;
@ -24,7 +24,7 @@ const getStyles = createStyle(() => {
stroke-width: 1px;
`,
};
});
};
type GraphTicksProps = {
numTicks: number;
@ -32,11 +32,12 @@ type GraphTicksProps = {
export default function GraphTicks(props: GraphTicksProps) {
const { numTicks } = props;
const styles = useStyles2(getStyles);
const ticks = [];
// i starts at 1, limit is `i < numTicks` so the first and last ticks aren't drawn
for (let i = 1; i < numTicks; i++) {
const x = `${(i / numTicks) * 100}%`;
ticks.push(<line className={getStyles().GraphTick} x1={x} y1="0%" x2={x} y2="100%" key={i / numTicks} />);
ticks.push(<line className={styles.GraphTick} x1={x} y1="0%" x2={x} y2="100%" key={i / numTicks} />);
}
return (

@ -14,11 +14,10 @@
import React from 'react';
import cx from 'classnames';
import { createStyle } from '../../Theme';
import { css } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
export const getStyles = createStyle(() => {
export const getStyles = () => {
return {
ScrubberHandleExpansion: cx(
css`
@ -70,7 +69,7 @@ export const getStyles = createStyle(() => {
}
`,
};
});
};
type ScrubberProps = {
isDragging: boolean;
@ -82,7 +81,7 @@ type ScrubberProps = {
export default function Scrubber({ isDragging, onMouseDown, onMouseEnter, onMouseLeave, position }: ScrubberProps) {
const xPercent = `${position * 100}%`;
const styles = getStyles();
const styles = useStyles2(getStyles);
const className = cx({ [styles.ScrubberDragging]: isDragging });
return (
<g className={className}>

@ -13,13 +13,12 @@
// limitations under the License.
import React from 'react';
import { css } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
import { formatDuration } from '../../utils/date';
import { createStyle } from '../../Theme';
import { css } from '@emotion/css';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
TickLabels: css`
label: TickLabels;
@ -34,7 +33,7 @@ const getStyles = createStyle(() => {
user-select: none;
`,
};
});
};
type TickLabelsProps = {
numTicks: number;
@ -43,7 +42,7 @@ type TickLabelsProps = {
export default function TickLabels(props: TickLabelsProps) {
const { numTicks, duration } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
const ticks = [];
for (let i = 0; i < numTicks + 1; i++) {

@ -14,13 +14,13 @@
import { shallow } from 'enzyme';
import React from 'react';
import { createTheme } from '@grafana/data';
import GraphTicks from './GraphTicks';
import Scrubber from './Scrubber';
import ViewingLayer, { dragTypes, getStyles } from './ViewingLayer';
import { EUpdateTypes } from '../../utils/DraggableManager';
import { polyfill as polyfillAnimationFrame } from '../../utils/test/requestAnimationFrame';
import { defaultTheme } from '../../Theme';
function getViewRange(viewStart, viewEnd) {
return {
@ -45,7 +45,6 @@ describe('<SpanGraph>', () => {
viewRange: getViewRange(0, 1),
};
wrapper = shallow(<ViewingLayer {...props} />)
.dive()
.dive()
.dive();
});
@ -54,7 +53,6 @@ describe('<SpanGraph>', () => {
beforeEach(() => {
props = { ...props, viewRange: getViewRange(0.1, 0.9) };
wrapper = shallow(<ViewingLayer {...props} />)
.dive()
.dive()
.dive();
wrapper.instance()._setRoot({
@ -130,7 +128,6 @@ describe('<SpanGraph>', () => {
const time = { ...props.viewRange.time, reframe: { anchor } };
props = { ...props, viewRange: { time } };
wrapper = shallow(<ViewingLayer {...props} />)
.dive()
.dive()
.dive();
wrapper.instance()._handleReframeDragUpdate({ value });
@ -160,7 +157,6 @@ describe('<SpanGraph>', () => {
const time = { ...props.viewRange.time, reframe: { anchor } };
props = { ...props, viewRange: { time } };
wrapper = shallow(<ViewingLayer {...props} />)
.dive()
.dive()
.dive();
wrapper.instance()._handleReframeDragEnd({ manager, value });
@ -176,7 +172,6 @@ describe('<SpanGraph>', () => {
const time = { ...props.viewRange.time, reframe: { anchor } };
props = { ...props, viewRange: { time } };
wrapper = shallow(<ViewingLayer {...props} />)
.dive()
.dive()
.dive();
wrapper.instance()._handleReframeDragEnd({ manager, value });
@ -274,28 +269,28 @@ describe('<SpanGraph>', () => {
describe('.ViewingLayer--resetZoom', () => {
it('should not render .ViewingLayer--resetZoom if props.viewRange.time.current = [0,1]', () => {
expect(wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`).length).toBe(0);
expect(wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`).length).toBe(0);
wrapper.setProps({ viewRange: { time: { current: [0, 1] } } });
expect(wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`).length).toBe(0);
expect(wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`).length).toBe(0);
});
it('should render ViewingLayer--resetZoom if props.viewRange.time.current[0] !== 0', () => {
// If the test fails on the following expect statement, this may be a false negative
expect(wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`).length).toBe(0);
expect(wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`).length).toBe(0);
wrapper.setProps({ viewRange: { time: { current: [0.1, 1] } } });
expect(wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`).length).toBe(1);
expect(wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`).length).toBe(1);
});
it('should render ViewingLayer--resetZoom if props.viewRange.time.current[1] !== 1', () => {
// If the test fails on the following expect statement, this may be a false negative
expect(wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`).length).toBe(0);
expect(wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`).length).toBe(0);
wrapper.setProps({ viewRange: { time: { current: [0, 0.9] } } });
expect(wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`).length).toBe(1);
expect(wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`).length).toBe(1);
});
it('should call props.updateViewRangeTime when clicked', () => {
wrapper.setProps({ viewRange: { time: { current: [0.1, 0.9] } } });
const resetZoomButton = wrapper.find(`.${getStyles(defaultTheme).ViewingLayerResetZoom}`);
const resetZoomButton = wrapper.find(`.${getStyles(createTheme()).ViewingLayerResetZoom}`);
// If the test fails on the following expect statement, this may be a false negative caused
// by a regression to rendering.
expect(resetZoomButton.length).toBe(1);
@ -313,11 +308,10 @@ describe('<SpanGraph>', () => {
it('renders a filtering box if leftBound exists', () => {
const _props = { ...props, viewRange: getViewRange(0.2, 1) };
wrapper = shallow(<ViewingLayer {..._props} />)
.dive()
.dive()
.dive();
const leftBox = wrapper.find(`.${getStyles(defaultTheme).ViewingLayerInactive}`);
const leftBox = wrapper.find(`.${getStyles(createTheme()).ViewingLayerInactive}`);
expect(leftBox.length).toBe(1);
const width = Number(leftBox.prop('width').slice(0, -1));
const x = leftBox.prop('x');
@ -328,11 +322,10 @@ describe('<SpanGraph>', () => {
it('renders a filtering box if rightBound exists', () => {
const _props = { ...props, viewRange: getViewRange(0, 0.8) };
wrapper = shallow(<ViewingLayer {..._props} />)
.dive()
.dive()
.dive();
const rightBox = wrapper.find(`.${getStyles(defaultTheme).ViewingLayerInactive}`);
const rightBox = wrapper.find(`.${getStyles(createTheme()).ViewingLayerInactive}`);
expect(rightBox.length).toBe(1);
const width = Number(rightBox.prop('width').slice(0, -1));
const x = Number(rightBox.prop('x').slice(0, -1));

@ -15,14 +15,16 @@
import cx from 'classnames';
import * as React from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { withTheme2, stylesFactory } from '@grafana/ui';
import GraphTicks from './GraphTicks';
import Scrubber from './Scrubber';
import { TUpdateViewRangeTimeFunction, UIButton, ViewRange, ViewRangeTimeUpdate, TNil } from '../..';
import { withTheme, Theme, autoColor, createStyle } from '../../Theme';
import { autoColor } from '../../Theme';
import DraggableManager, { DraggableBounds, DraggingUpdate, EUpdateTypes } from '../../utils/DraggableManager';
export const getStyles = createStyle((theme: Theme) => {
export const getStyles = stylesFactory((theme: GrafanaTheme2) => {
// Need this cause emotion will merge emotion generated classes into single className if used with cx from emotion
// package and the selector won't work
const ViewingLayerResetZoomHoverClassName = 'JaegerUiComponents__ViewingLayerResetZoomHoverClassName';
@ -91,7 +93,7 @@ type ViewingLayerProps = {
updateViewRangeTime: TUpdateViewRangeTimeFunction;
updateNextViewRangeTime: (update: ViewRangeTimeUpdate) => void;
viewRange: ViewRange;
theme: Theme;
theme: GrafanaTheme2;
};
type ViewingLayerState = {
@ -406,4 +408,4 @@ export class UnthemedViewingLayer extends React.PureComponent<ViewingLayerProps,
}
}
export default withTheme(UnthemedViewingLayer);
export default withTheme2(UnthemedViewingLayer);

@ -17,10 +17,12 @@ import { get as _get, maxBy as _maxBy, values as _values } from 'lodash';
import MdKeyboardArrowRight from 'react-icons/lib/md/keyboard-arrow-right';
import { css } from '@emotion/css';
import cx from 'classnames';
import { dateTimeFormat, GrafanaTheme2, TimeZone } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import SpanGraph from './SpanGraph';
import TracePageSearchBar from './TracePageSearchBar';
import { autoColor, Theme, TUpdateViewRangeTimeFunction, useTheme, ViewRange, ViewRangeTimeUpdate } from '..';
import { autoColor, TUpdateViewRangeTimeFunction, ViewRange, ViewRangeTimeUpdate } from '..';
import LabeledList from '../common/LabeledList';
import TraceName from '../common/TraceName';
import { getTraceName } from '../model/trace-viewer';
@ -30,11 +32,9 @@ import { formatDuration } from '../utils/date';
import { getTraceLinks } from '../model/link-patterns';
import ExternalLinks from '../common/ExternalLinks';
import { createStyle } from '../Theme';
import { uTxMuted } from '../uberUtilityStyles';
import { dateTimeFormat, TimeZone } from '@grafana/data';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
TracePageHeader: css`
label: TracePageHeader;
@ -135,7 +135,7 @@ const getStyles = createStyle((theme: Theme) => {
white-space: nowrap;
`,
};
});
};
type TracePageHeaderEmbedProps = {
canCollapse: boolean;
@ -225,7 +225,7 @@ export default function TracePageHeader(props: TracePageHeaderEmbedProps) {
timeZone,
} = props;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
const links = React.useMemo(() => {
if (!trace) {
return [];

@ -16,18 +16,18 @@ import * as React from 'react';
import cx from 'classnames';
import IoAndroidLocate from 'react-icons/lib/io/android-locate';
import { css } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
import * as markers from './TracePageSearchBar.markers';
import UiFindInput from '../common/UiFindInput';
import { TNil } from '../types';
import { UIButton, UIInputGroup } from '../uiElementsContext';
import { createStyle } from '../Theme';
import { ubFlexAuto, ubJustifyEnd } from '../uberUtilityStyles';
// eslint-disable-next-line no-duplicate-imports
import { memo } from 'react';
export const getStyles = createStyle(() => {
export const getStyles = () => {
return {
TracePageSearchBar: css`
label: TracePageSearchBar;
@ -58,7 +58,7 @@ export const getStyles = createStyle(() => {
padding: 1px 8px 4px;
`,
};
});
};
type TracePageSearchBarProps = {
textFilter: string | TNil;
@ -86,7 +86,7 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps)
searchValue,
hideSearchButtons,
} = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
const count = textFilter ? <span className={styles.TracePageSearchBarCount}>{resultCount}</span> : null;

@ -14,14 +14,14 @@
import React from 'react';
import { css } from '@emotion/css';
import { stylesFactory } from '@grafana/ui';
import NewWindowIcon from '../common/NewWindowIcon';
import { TraceSpanReference } from '../types/trace';
import { UITooltip, UIDropdown, UIMenuItem, UIMenu, TooltipPlacement } from '../uiElementsContext';
import ReferenceLink from '../url/ReferenceLink';
import { createStyle } from '../Theme';
export const getStyles = createStyle(() => {
export const getStyles = stylesFactory(() => {
return {
MultiParent: css`
padding: 0 5px;

@ -17,14 +17,16 @@ import { css } from '@emotion/css';
import { groupBy as _groupBy } from 'lodash';
import React from 'react';
import { compose, onlyUpdateForKeys, withProps, withState } from 'recompose';
import { autoColor, createStyle, Theme } from '../Theme';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { autoColor } from '../Theme';
import { TraceSpan } from '../types/trace';
import { TNil } from '../types';
import { UIPopover } from '../uiElementsContext';
import AccordianLogs from './SpanDetail/AccordianLogs';
import { ViewedBoundsFunctionType } from './utils';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
wrapper: css`
label: wrapper;
@ -86,7 +88,7 @@ const getStyles = createStyle((theme: Theme) => {
}
`,
};
});
};
type TCommonProps = {
color: string;
@ -105,7 +107,6 @@ type TCommonProps = {
span: TraceSpan;
className?: string;
labelClassName?: string;
theme: Theme;
};
type TInnerProps = {
@ -136,7 +137,6 @@ function SpanBar(props: TInnerProps) {
rpc,
traceStartTime,
span,
theme,
className,
labelClassName,
} = props;
@ -146,7 +146,7 @@ function SpanBar(props: TInnerProps) {
// round to the nearest 0.2%
return toPercent(Math.round(posPercent * 500) / 500);
});
const styles = getStyles(theme);
const styles = useStyles2(getStyles);
return (
<div

@ -19,6 +19,8 @@ import IoNetwork from 'react-icons/lib/io/network';
import MdFileUpload from 'react-icons/lib/md/file-upload';
import { css } from '@emotion/css';
import cx from 'classnames';
import { stylesFactory, withTheme2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import ReferencesButton from './ReferencesButton';
import TimelineRow from './TimelineRow';
@ -29,7 +31,7 @@ import Ticks from './Ticks';
import { SpanLinkFunc, TNil } from '../types';
import { TraceSpan } from '../types/trace';
import { autoColor, createStyle, Theme, withTheme } from '../Theme';
import { autoColor } from '../Theme';
const spanBarClassName = 'spanBar';
const spanBarLabelClassName = 'spanBarLabel';
@ -38,7 +40,7 @@ const nameWrapperMatchingFilterClassName = 'nameWrapperMatchingFilter';
const viewClassName = 'jaegerView';
const nameColumnClassName = 'nameColumn';
const getStyles = createStyle((theme: Theme) => {
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
nameWrapper: css`
label: nameWrapper;
@ -260,7 +262,7 @@ const getStyles = createStyle((theme: Theme) => {
type SpanBarRowProps = {
className?: string;
theme: Theme;
theme: GrafanaTheme2;
color: string;
columnDivision: number;
isChildrenExpanded: boolean;
@ -505,7 +507,6 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
rpc={rpc}
viewStart={viewStart}
viewEnd={viewEnd}
theme={theme}
getViewedBounds={getViewedBounds}
color={color}
shortLabel={label}
@ -521,4 +522,4 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
}
}
export default withTheme(UnthemedSpanBarRow);
export default withTheme2(UnthemedSpanBarRow);

@ -22,10 +22,12 @@ import * as markers from './AccordianKeyValues.markers';
import KeyValuesTable from './KeyValuesTable';
import { TNil } from '../../types';
import { TraceKeyValuePair, TraceLink } from '../../types/trace';
import { autoColor, createStyle, Theme, useTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { uAlignIcon, uTxEllipsis } from '../../uberUtilityStyles';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
export const getStyles = createStyle((theme: Theme) => {
export const getStyles = (theme: GrafanaTheme2) => {
return {
header: css`
label: header;
@ -80,7 +82,7 @@ export const getStyles = createStyle((theme: Theme) => {
padding: 0 0.2em;
`,
};
});
};
type AccordianKeyValuesProps = {
className?: string | TNil;
@ -96,7 +98,7 @@ type AccordianKeyValuesProps = {
// export for tests
export function KeyValuesSummary(props: { data?: TraceKeyValuePair[] }) {
const { data } = props;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
if (!Array.isArray(data) || !data.length) {
return null;
@ -123,7 +125,7 @@ KeyValuesSummary.defaultProps = {
export default function AccordianKeyValues(props: AccordianKeyValuesProps) {
const { className, data, highContrast, interactive, isOpen, label, linksGetter, onToggle } = props;
const isEmpty = !Array.isArray(data) || !data.length;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
const iconCls = cx(uAlignIcon, { [styles.emptyIcon]: isEmpty });
let arrow: React.ReactNode | null = null;
let headerProps: {} | null = null;

@ -17,15 +17,17 @@ import { sortBy as _sortBy } from 'lodash';
import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down';
import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right';
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import AccordianKeyValues from './AccordianKeyValues';
import { formatDuration } from '../utils';
import { TNil } from '../../types';
import { TraceLog, TraceKeyValuePair, TraceLink } from '../../types/trace';
import { autoColor, createStyle, Theme, useTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { uAlignIcon, ubMb1 } from '../../uberUtilityStyles';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
AccordianLogs: css`
label: AccordianLogs;
@ -54,7 +56,7 @@ const getStyles = createStyle((theme: Theme) => {
color: ${autoColor(theme, '#999')};
`,
};
});
};
type AccordianLogsProps = {
interactive?: boolean;
@ -82,7 +84,7 @@ export default function AccordianLogs(props: AccordianLogsProps) {
};
}
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<div className={styles.AccordianLogs}>
<HeaderComponent className={styles.AccordianLogsHeader} {...headerProps}>

@ -15,16 +15,15 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down';
import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right';
import { TraceSpanReference } from '../../types/trace';
import ReferenceLink from '../../url/ReferenceLink';
import { createStyle } from '../../Theme';
import { uAlignIcon } from '../../uberUtilityStyles';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
ReferencesList: css`
background: #fff;
@ -63,7 +62,7 @@ const getStyles = createStyle(() => {
}
`,
};
});
};
type AccordianReferencesProps = {
data: TraceSpanReference[];
@ -82,7 +81,7 @@ type ReferenceItemProps = {
// export for test
export function References(props: ReferenceItemProps) {
const { data, focusSpan } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
return (
<div className={cx(styles.ReferencesList)}>

@ -17,13 +17,16 @@ import { css } from '@emotion/css';
import cx from 'classnames';
import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down';
import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import TextList from './TextList';
import { TNil } from '../../types';
import { getStyles as getAccordianKeyValuesStyles } from './AccordianKeyValues';
import { autoColor, createStyle, Theme, useTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { uAlignIcon } from '../../uberUtilityStyles';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
header: css`
cursor: pointer;
@ -36,7 +39,7 @@ const getStyles = createStyle((theme: Theme) => {
}
`,
};
});
};
type AccordianTextProps = {
className?: string | TNil;
@ -66,7 +69,7 @@ export default function AccordianText(props: AccordianTextProps) {
TextComponent = DefaultTextComponent,
} = props;
const isEmpty = !Array.isArray(data) || !data.length;
const accordianKeyValuesStyles = getAccordianKeyValuesStyles(useTheme());
const accordianKeyValuesStyles = useStyles2(getAccordianKeyValuesStyles);
const iconCls = cx(uAlignIcon, { [accordianKeyValuesStyles.emptyIcon]: isEmpty });
let arrow: React.ReactNode | null = null;
let headerProps: {} | null = null;
@ -78,7 +81,7 @@ export default function AccordianText(props: AccordianTextProps) {
role: 'switch',
};
}
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<div className={className || ''}>
<div className={cx(styles.header, headerClassName)} {...headerProps} data-test-id="AccordianText--header">

@ -14,13 +14,13 @@
import React from 'react';
import { shallow } from 'enzyme';
import { createTheme } from '@grafana/data';
import CopyIcon from '../../common/CopyIcon';
import KeyValuesTable, { LinkValue, getStyles } from './KeyValuesTable';
import { UIDropdown, UIIcon } from '../../uiElementsContext';
import { ubInlineBlock } from '../../uberUtilityStyles';
import { defaultTheme } from '../../Theme';
describe('LinkValue', () => {
const title = 'titleValue';
@ -39,7 +39,7 @@ describe('LinkValue', () => {
});
it('renders correct Icon', () => {
const styles = getStyles(defaultTheme);
const styles = getStyles(createTheme());
expect(wrapper.find(UIIcon).hasClass(styles.linkIcon)).toBe(true);
expect(wrapper.find(UIIcon).prop('type')).toBe('export');
});

@ -16,18 +16,19 @@ import * as React from 'react';
import jsonMarkup from 'json-markup';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import CopyIcon from '../../common/CopyIcon';
import { TNil } from '../../types';
import { TraceKeyValuePair, TraceLink } from '../../types/trace';
import { UIDropdown, UIIcon, UIMenu, UIMenuItem } from '../../uiElementsContext';
import { autoColor, createStyle, Theme, useTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { ubInlineBlock, uWidth100 } from '../../uberUtilityStyles';
const copyIconClassName = 'copyIcon';
export const getStyles = createStyle((theme: Theme) => {
export const getStyles = (theme: GrafanaTheme2) => {
return {
KeyValueTable: css`
label: KeyValueTable;
@ -71,7 +72,7 @@ export const getStyles = createStyle((theme: Theme) => {
font-weight: bold;
`,
};
});
};
const jsonObjectOrArrayStartRegex = /^(\[|\{)/;
@ -88,7 +89,7 @@ function parseIfComplexJson(value: any) {
}
export const LinkValue = (props: { href: string; title?: string; children: React.ReactNode }) => {
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<a href={props.href} title={props.title} target="_blank" rel="noopener noreferrer">
{props.children} <UIIcon className={styles.linkIcon} type="export" />
@ -118,7 +119,7 @@ type KeyValuesTableProps = {
export default function KeyValuesTable(props: KeyValuesTableProps) {
const { data, linksGetter } = props;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<div className={cx(styles.KeyValueTable)} data-test-id="KeyValueTable">
<table className={uWidth100}>

@ -15,10 +15,9 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import { createStyle } from '../../Theme';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
TextList: css`
max-height: 450px;
@ -38,7 +37,7 @@ const getStyles = createStyle(() => {
}
`,
};
});
};
type TextListProps = {
data: string[];
@ -46,7 +45,7 @@ type TextListProps = {
export default function TextList(props: TextListProps) {
const { data } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
return (
<div className={cx(styles.TextList)} data-test-id="TextList">
<ul className={styles.List}>

@ -15,6 +15,8 @@
import React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { DataLinkButton, TextArea, useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import AccordianKeyValues from './AccordianKeyValues';
import AccordianLogs from './AccordianLogs';
@ -23,16 +25,14 @@ import DetailState from './DetailState';
import { formatDuration } from '../utils';
import CopyIcon from '../../common/CopyIcon';
import LabeledList from '../../common/LabeledList';
import { SpanLinkFunc, TNil } from '../../types';
import { TraceKeyValuePair, TraceLink, TraceLog, TraceSpan } from '../../types/trace';
import AccordianReferences from './AccordianReferences';
import { autoColor, createStyle, Theme, useTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { UIDivider } from '../../uiElementsContext';
import { ubFlex, ubFlexAuto, ubItemsCenter, ubM0, ubMb1, ubMy1, ubTxRightAlign } from '../../uberUtilityStyles';
import { DataLinkButton, TextArea } from '@grafana/ui';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
divider: css`
label: divider;
@ -100,7 +100,7 @@ const getStyles = createStyle((theme: Theme) => {
white-space: pre;
`,
};
});
};
type SpanDetailProps = {
detailState: DetailState;
@ -172,7 +172,7 @@ export default function SpanDetail(props: SpanDetailProps) {
},
];
const deepLinkCopyText = `${window.location.origin}${window.location.pathname}?uiFind=${spanID}`;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
const link = createSpanLink?.(span);
return (

@ -14,8 +14,9 @@
import React from 'react';
import { shallow } from 'enzyme';
import { createTheme } from '@grafana/data';
import SpanDetailRow from './SpanDetailRow';
import { UnthemedSpanDetailRow } from './SpanDetailRow';
import SpanDetail from './SpanDetail';
import DetailState from './SpanDetail/DetailState';
import SpanTreeOffset from './SpanTreeOffset';
@ -37,6 +38,7 @@ describe('<SpanDetailRow>', () => {
span: { spanID, depth: 3 },
tagsToggle: jest.fn(),
traceStartTime: 1000,
theme: createTheme(),
};
let wrapper;
@ -48,10 +50,7 @@ describe('<SpanDetailRow>', () => {
props.logsToggle.mockReset();
props.processToggle.mockReset();
props.tagsToggle.mockReset();
wrapper = shallow(<SpanDetailRow {...props} />)
.dive()
.dive()
.dive();
wrapper = shallow(<UnthemedSpanDetailRow {...props} />);
});
it('renders without exploding', () => {

@ -19,12 +19,14 @@ import SpanDetail from './SpanDetail';
import DetailState from './SpanDetail/DetailState';
import SpanTreeOffset from './SpanTreeOffset';
import TimelineRow from './TimelineRow';
import { autoColor, createStyle, Theme, withTheme } from '../Theme';
import { autoColor } from '../Theme';
import { stylesFactory, withTheme2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { TraceLog, TraceSpan, TraceKeyValuePair, TraceLink } from '../types/trace';
import { SpanLinkFunc } from '../types';
const getStyles = createStyle((theme: Theme) => {
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
expandedAccent: css`
cursor: pointer;
@ -85,7 +87,7 @@ type SpanDetailRowProps = {
hoverIndentGuideIds: Set<string>;
addHoverIndentGuideId: (spanID: string) => void;
removeHoverIndentGuideId: (spanID: string) => void;
theme: Theme;
theme: GrafanaTheme2;
createSpanLink?: SpanLinkFunc;
};
@ -166,4 +168,4 @@ export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProp
}
}
export default withTheme(UnthemedSpanDetailRow);
export default withTheme2(UnthemedSpanDetailRow);

@ -16,10 +16,10 @@ import { shallow } from 'enzyme';
import React from 'react';
import IoChevronRight from 'react-icons/lib/io/chevron-right';
import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down';
import { createTheme } from '@grafana/data';
import SpanTreeOffset, { getStyles } from './SpanTreeOffset';
import spanAncestorIdsSpy from '../utils/span-ancestor-ids';
import { defaultTheme } from '../Theme';
jest.mock('../utils/span-ancestor-ids');
@ -44,7 +44,6 @@ describe('SpanTreeOffset', () => {
},
};
wrapper = shallow(<SpanTreeOffset {...props} />)
.dive()
.dive()
.dive();
});
@ -53,7 +52,6 @@ describe('SpanTreeOffset', () => {
it('renders only one .SpanTreeOffset--indentGuide for entire trace if span has no ancestors', () => {
spanAncestorIdsSpy.mockReturnValue([]);
wrapper = shallow(<SpanTreeOffset {...props} />)
.dive()
.dive()
.dive();
const indentGuides = wrapper.find('[data-test-id="SpanTreeOffset--indentGuide"]');
@ -72,10 +70,9 @@ describe('SpanTreeOffset', () => {
it('adds .is-active to correct indentGuide', () => {
props.hoverIndentGuideIds = new Set([parentSpanID]);
wrapper = shallow(<SpanTreeOffset {...props} />)
.dive()
.dive()
.dive();
const styles = getStyles(defaultTheme);
const styles = getStyles(createTheme());
const activeIndentGuide = wrapper.find(`.${styles.indentGuideActive}`);
expect(activeIndentGuide.length).toBe(1);
expect(activeIndentGuide.prop('data-ancestor-id')).toBe(parentSpanID);

@ -18,13 +18,14 @@ import IoChevronRight from 'react-icons/lib/io/chevron-right';
import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down';
import { css } from '@emotion/css';
import cx from 'classnames';
import { GrafanaTheme2 } from '@grafana/data';
import { stylesFactory, withTheme2 } from '@grafana/ui';
import { TraceSpan } from '../types/trace';
import spanAncestorIds from '../utils/span-ancestor-ids';
import { autoColor } from '../Theme';
import { autoColor, createStyle, Theme, withTheme } from '../Theme';
export const getStyles = createStyle((theme: Theme) => {
export const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
SpanTreeOffset: css`
label: SpanTreeOffset;
@ -74,7 +75,7 @@ type TProps = {
hoverIndentGuideIds: Set<string>;
addHoverIndentGuideId: (spanID: string) => void;
removeHoverIndentGuideId: (spanID: string) => void;
theme: Theme;
theme: GrafanaTheme2;
};
export class UnthemedSpanTreeOffset extends React.PureComponent<TProps> {
@ -167,4 +168,4 @@ export class UnthemedSpanTreeOffset extends React.PureComponent<TProps> {
}
}
export default withTheme(UnthemedSpanTreeOffset);
export default withTheme2(UnthemedSpanTreeOffset);

@ -15,12 +15,14 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { formatDuration } from './utils';
import { TNil } from '../types';
import { autoColor, createStyle, Theme, useTheme } from '../Theme';
import { autoColor } from '../Theme';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
Ticks: css`
label: Ticks;
@ -47,7 +49,7 @@ const getStyles = createStyle((theme: Theme) => {
right: 0.25rem;
`,
};
});
};
type TicksProps = {
endTime?: number | TNil;
@ -68,7 +70,7 @@ export default function Ticks(props: TicksProps) {
labels.push(formatDuration(durationAtTick));
}
}
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
const ticks: React.ReactNode[] = [];
for (let i = 0; i < numTicks; i++) {
const portion = i / (numTicks - 1);

@ -12,12 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { IconButton } from '@grafana/ui';
import { IconButton, useStyles2 } from '@grafana/ui';
import { css } from '@emotion/css';
import React from 'react';
import { createStyle } from '../../Theme';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
TimelineCollapser: css`
align-items: center;
@ -27,7 +26,7 @@ const getStyles = createStyle(() => {
margin-right: 0.5rem;
`,
};
});
};
type CollapserProps = {
onCollapseAll: () => void;
@ -38,7 +37,7 @@ type CollapserProps = {
export function TimelineCollapser(props: CollapserProps) {
const { onExpandAll, onExpandOne, onCollapseAll, onCollapseOne } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
return (
<div className={styles.TimelineCollapser} data-test-id="TimelineCollapser">
<IconButton tooltip="Expand +1" size="xl" tooltipPlacement="top" name="angle-down" onClick={onExpandOne} />

@ -15,12 +15,12 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { stylesFactory } from '@grafana/ui';
import { TNil } from '../../types';
import DraggableManager, { DraggableBounds, DraggingUpdate } from '../../utils/DraggableManager';
import { createStyle } from '../../Theme';
export const getStyles = createStyle(() => {
export const getStyles = stylesFactory(() => {
return {
TimelineColumnResizer: css`
left: 0;

@ -15,6 +15,8 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { TimelineCollapser } from './TimelineCollapser';
import TimelineColumnResizer from './TimelineColumnResizer';
@ -22,10 +24,10 @@ import TimelineViewingLayer from './TimelineViewingLayer';
import Ticks from '../Ticks';
import TimelineRow from '../TimelineRow';
import { TUpdateViewRangeTimeFunction, ViewRangeTime, ViewRangeTimeUpdate } from '../types';
import { autoColor, createStyle, Theme, useTheme } from '../../Theme';
import { autoColor } from '../../Theme';
import { ubFlex, ubPx2 } from '../../uberUtilityStyles';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
TimelineHeaderRow: css`
label: TimelineHeaderRow;
@ -50,7 +52,7 @@ const getStyles = createStyle((theme: Theme) => {
align-items: center;
`,
};
});
};
type TimelineHeaderRowProps = {
duration: number;
@ -83,7 +85,7 @@ export default function TimelineHeaderRow(props: TimelineHeaderRowProps) {
columnResizeHandleHeight,
} = props;
const [viewStart, viewEnd] = viewRangeTime.current;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<TimelineRow className={styles.TimelineHeaderRow} data-test-id="TimelineHeaderRow">
<TimelineRow.Cell className={cx(ubFlex, ubPx2, styles.TimelineHeaderWrapper)} width={nameColumnWidth}>

@ -14,14 +14,13 @@
import * as React from 'react';
import { css, cx } from '@emotion/css';
import { stylesFactory } from '@grafana/ui';
import { TUpdateViewRangeTimeFunction, ViewRangeTime, ViewRangeTimeUpdate } from '../types';
import { TNil } from '../../types';
import DraggableManager, { DraggableBounds, DraggingUpdate } from '../../utils/DraggableManager';
import { createStyle } from '../../Theme';
// exported for testing
export const getStyles = createStyle(() => {
export const getStyles = stylesFactory(() => {
return {
TimelineViewingLayer: css`
label: TimelineViewingLayer;

@ -15,10 +15,10 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { createStyle } from '../Theme';
import { useStyles2 } from '@grafana/ui';
import { ubRelative } from '../uberUtilityStyles';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
flexRow: css`
display: flex;
@ -26,7 +26,7 @@ const getStyles = createStyle(() => {
flex-direction: row;
`,
};
});
};
type TTimelineRowProps = {
children: React.ReactNode;
@ -42,7 +42,7 @@ interface TimelineRowCellProps extends React.HTMLAttributes<HTMLDivElement> {
export default function TimelineRow(props: TTimelineRowProps) {
const { children, className = '', ...rest } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
return (
<div className={cx(styles.flexRow, className)} {...rest}>
{children}

@ -90,7 +90,6 @@ describe('<VirtualizedTraceViewImpl>', () => {
}
});
wrapper = shallow(<VirtualizedTraceView {...props} />)
.dive()
.dive()
.dive();
instance = wrapper.instance();

@ -17,6 +17,9 @@ import { css } from '@emotion/css';
import { isEqual } from 'lodash';
import memoizeOne from 'memoize-one';
import { stylesFactory, withTheme2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import ListView from './ListView';
import SpanBarRow from './SpanBarRow';
import DetailState from './SpanDetail/DetailState';
@ -36,13 +39,11 @@ import { TraceLog, TraceSpan, Trace, TraceKeyValuePair, TraceLink } from '../typ
import TTraceTimeline from '../types/TTraceTimeline';
import { PEER_SERVICE } from '../constants/tag-keys';
import { createStyle, Theme, withTheme } from '../Theme';
type TExtractUiFindFromStateReturn = {
uiFind: string | undefined;
};
const getStyles = createStyle(() => {
const getStyles = stylesFactory(() => {
return {
rowsWrapper: css`
width: 100%;
@ -82,7 +83,7 @@ type TVirtualizedTraceViewOwnProps = {
hoverIndentGuideIds: Set<string>;
addHoverIndentGuideId: (spanID: string) => void;
removeHoverIndentGuideId: (spanID: string) => void;
theme: Theme;
theme: GrafanaTheme2;
createSpanLink?: SpanLinkFunc;
scrollElement?: Element;
};
@ -486,4 +487,4 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
}
}
export default withTheme(UnthemedVirtualizedTraceView);
export default withTheme2(UnthemedVirtualizedTraceView);

@ -14,12 +14,12 @@
import React from 'react';
import { shallow } from 'enzyme';
import { createTheme } from '@grafana/data';
import TraceTimelineViewer from './index';
import traceGenerator from '../demo/trace-generators';
import transformTraceData from '../model/transform-trace-data';
import TimelineHeaderRow from './TimelineHeaderRow';
import { defaultTheme } from '../Theme';
describe('<TraceTimelineViewer>', () => {
const trace = transformTraceData(traceGenerator.trace({}));
@ -38,7 +38,7 @@ describe('<TraceTimelineViewer>', () => {
collapseAll: jest.fn(),
expandOne: jest.fn(),
collapseOne: jest.fn(),
theme: defaultTheme,
theme: createTheme(),
history: {
replace: () => {},
},

@ -14,6 +14,8 @@
import React from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { stylesFactory, withTheme2 } from '@grafana/ui';
import TimelineHeaderRow from './TimelineHeaderRow';
import VirtualizedTraceView from './VirtualizedTraceView';
@ -23,14 +25,14 @@ import { TUpdateViewRangeTimeFunction, ViewRange, ViewRangeTimeUpdate } from './
import { SpanLinkFunc, TNil } from '../types';
import { TraceSpan, Trace, TraceLog, TraceKeyValuePair, TraceLink } from '../types/trace';
import TTraceTimeline from '../types/TTraceTimeline';
import { autoColor, createStyle, Theme, withTheme } from '../Theme';
import { autoColor } from '../Theme';
import ExternalLinkContext from '../url/externalLinkContext';
type TExtractUiFindFromStateReturn = {
uiFind: string | undefined;
};
const getStyles = createStyle((theme: Theme) => {
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
return {
TraceTimelineViewer: css`
label: TraceTimelineViewer;
@ -98,7 +100,7 @@ type TProps = TExtractUiFindFromStateReturn & {
addHoverIndentGuideId: (spanID: string) => void;
removeHoverIndentGuideId: (spanID: string) => void;
linksGetter: (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => TraceLink[];
theme: Theme;
theme: GrafanaTheme2;
createSpanLink?: SpanLinkFunc;
scrollElement?: Element;
};
@ -193,4 +195,4 @@ export class UnthemedTraceTimelineViewer extends React.PureComponent<TProps, Sta
}
}
export default withTheme(UnthemedTraceTimelineViewer);
export default withTheme2(UnthemedTraceTimelineViewer);

@ -14,10 +14,9 @@
import * as React from 'react';
import { css } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
import { createStyle } from '../Theme';
const getStyles = createStyle(() => {
const getStyles = () => {
return {
BreakableText: css`
label: BreakableText;
@ -25,7 +24,7 @@ const getStyles = createStyle(() => {
white-space: pre;
`,
};
});
};
const WORD_RX = /\W*\w+\W*/g;
@ -41,6 +40,7 @@ export default function BreakableText(
props: Props
): any /* React.ReactNode /* React.ReactElement | React.ReactElement[] \*\/ */ {
const { className, text, wordRegexp = WORD_RX } = props;
const styles = useStyles2(getStyles);
if (!text) {
return typeof text === 'string' ? text : null;
}
@ -50,7 +50,7 @@ export default function BreakableText(
let match: RegExpExecArray | string[] | null = wordRegexp.exec(text) || [text];
while (match) {
spans.push(
<span key={`${text}-${spans.length}`} className={className || getStyles().BreakableText}>
<span key={`${text}-${spans.length}`} className={className || styles.BreakableText}>
{match[0]}
</span>
);

@ -16,11 +16,11 @@ import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import copy from 'copy-to-clipboard';
import { stylesFactory } from '@grafana/ui';
import { UITooltip, TooltipPlacement, UIButton } from '../uiElementsContext';
import { createStyle } from '../Theme';
const getStyles = createStyle(() => {
const getStyles = stylesFactory(() => {
return {
CopyIcon: css`
background-color: transparent;

@ -15,11 +15,12 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import { createStyle, isLight, Theme, useTheme } from '../Theme';
import { UIDivider } from '../uiElementsContext';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
LabeledList: css`
label: LabeledList;
@ -33,11 +34,11 @@ const getStyles = createStyle((theme: Theme) => {
`,
LabeledListLabel: css`
label: LabeledListLabel;
color: ${isLight(theme) ? '#999' : '#666'};
color: ${theme.isLight ? '#999' : '#666'};
margin-right: 0.25rem;
`,
};
});
};
type LabeledListProps = {
className?: string;
@ -47,7 +48,7 @@ type LabeledListProps = {
export default function LabeledList(props: LabeledListProps) {
const { className, dividerClassName, items } = props;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
return (
<ul className={cx(styles.LabeledList, className)}>
{items.map(({ key, label, value }, i) => {

@ -15,11 +15,11 @@
import React from 'react';
import cx from 'classnames';
import { css, keyframes } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
import { createStyle } from '../Theme';
import { UIIcon } from '../uiElementsContext';
const getStyles = createStyle(() => {
const getStyles = () => {
const LoadingIndicatorColorAnim = keyframes`
/*
rgb(0, 128, 128) == teal
@ -52,7 +52,7 @@ const getStyles = createStyle(() => {
font-size: 0.7em;
`,
};
});
};
type LoadingIndicatorProps = {
centered?: boolean;
@ -62,7 +62,7 @@ type LoadingIndicatorProps = {
export default function LoadingIndicator(props: LoadingIndicatorProps) {
const { centered, className, small, ...rest } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
const cls = cx(styles.LoadingIndicator, {
[styles.LoadingIndicatorCentered]: centered,
[styles.LoadingIndicatorSmall]: small,

@ -16,17 +16,16 @@ import React from 'react';
import cx from 'classnames';
import IoAndroidOpen from 'react-icons/lib/io/android-open';
import { css } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
import { createStyle } from '../Theme';
export const getStyles = createStyle(() => {
export const getStyles = () => {
return {
NewWindowIconLarge: css`
label: NewWindowIconLarge;
font-size: 1.5em;
`,
};
});
};
type Props = {
isLarge?: boolean;
@ -35,7 +34,7 @@ type Props = {
export default function NewWindowIcon(props: Props) {
const { isLarge, className, ...rest } = props;
const styles = getStyles();
const styles = useStyles2(getStyles);
const cls = cx({ [styles.NewWindowIconLarge]: isLarge }, className);
return <IoAndroidOpen className={cls} {...rest} />;
}

@ -15,27 +15,27 @@
import * as React from 'react';
import { css } from '@emotion/css';
import cx from 'classnames';
import { useStyles2 } from '@grafana/ui';
import { GrafanaTheme2 } from '@grafana/data';
import BreakableText from './BreakableText';
import LoadingIndicator from './LoadingIndicator';
import { fetchedState, FALLBACK_TRACE_NAME } from '../constants';
import { FetchedState, TNil } from '../types';
import { ApiError } from '../types/api-error';
import { createStyle, safeSize, Theme, useTheme } from '../Theme';
const getStyles = createStyle((theme: Theme) => {
const getStyles = (theme: GrafanaTheme2) => {
return {
TraceName: css`
label: TraceName;
font-size: ${safeSize(theme.components?.TraceName?.fontSize, 'unset')};
font-size: ${theme.typography.size.lg};
`,
TraceNameError: css`
label: TraceNameError;
color: #c00;
`,
};
});
};
type Props = {
className?: string;
@ -48,7 +48,7 @@ export default function TraceName(props: Props) {
const { className, error, state, traceName } = props;
const isErred = state === fetchedState.ERROR;
let title: string | React.ReactNode = traceName || FALLBACK_TRACE_NAME;
const styles = getStyles(useTheme());
const styles = useStyles2(getStyles);
let errorCssClass = '';
if (isErred) {
errorCssClass = styles.TraceNameError;

@ -13,26 +13,26 @@
// limitations under the License.
import { getColorByKey, clear } from './color-generator';
import { defaultTheme } from '../Theme';
import { createTheme } from '@grafana/data';
it('gives the same color for the same key', () => {
clear();
const colorOne = getColorByKey('serviceA', defaultTheme);
const colorTwo = getColorByKey('serviceA', defaultTheme);
const colorOne = getColorByKey('serviceA', createTheme());
const colorTwo = getColorByKey('serviceA', createTheme());
expect(colorOne).toBe(colorTwo);
});
it('gives different colors for each for each key', () => {
clear();
const colorOne = getColorByKey('serviceA', defaultTheme);
const colorTwo = getColorByKey('serviceB', defaultTheme);
const colorOne = getColorByKey('serviceA', createTheme());
const colorTwo = getColorByKey('serviceB', createTheme());
expect(colorOne).not.toBe(colorTwo);
});
it('should clear cache', () => {
clear();
const colorOne = getColorByKey('serviceA', defaultTheme);
const colorOne = getColorByKey('serviceA', createTheme());
clear();
const colorTwo = getColorByKey('serviceB', defaultTheme);
const colorTwo = getColorByKey('serviceB', createTheme());
expect(colorOne).toBe(colorTwo);
});

@ -12,8 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Theme } from '../Theme';
import memoizeOne from 'memoize-one';
import { GrafanaTheme2 } from '@grafana/data';
import { colors } from '@grafana/ui';
// TS needs the precise return type
function strToRgb(s: string): [number, number, number] {
@ -83,10 +84,10 @@ export function clear() {
getGenerator([]);
}
export function getColorByKey(key: string, theme: Theme) {
return getGenerator(theme.servicesColorPalette).getColorByKey(key);
export function getColorByKey(key: string, theme: GrafanaTheme2) {
return getGenerator(colors).getColorByKey(key);
}
export function getRgbColorByKey(key: string, theme: Theme): [number, number, number] {
return getGenerator(theme.servicesColorPalette).getRgbColorByKey(key);
export function getRgbColorByKey(key: string, theme: GrafanaTheme2): [number, number, number] {
return getGenerator(colors).getRgbColorByKey(key);
}

@ -1,9 +1,5 @@
import { DataFrame, DataFrameView, SplitOpen, TraceSpanRow } from '@grafana/data';
import { colors, useTheme } from '@grafana/ui';
import {
ThemeOptions,
ThemeProvider,
ThemeType,
Trace,
TracePageHeader,
TraceProcess,
@ -75,21 +71,6 @@ export function TraceView(props: Props) {
?.tracesToLogs;
const timeZone = useSelector((state: StoreState) => getTimeZone(state.user));
const theme = useTheme();
const traceTheme = useMemo(
() =>
({
type: theme.isDark ? ThemeType.Dark : ThemeType.Light,
servicesColorPalette: colors,
components: {
TraceName: {
fontSize: theme.typography.size.lg,
},
},
} as ThemeOptions),
[theme]
);
const traceTimeline: TTraceTimeline = useMemo(
() => ({
childrenHiddenIDs,
@ -113,67 +94,65 @@ export function TraceView(props: Props) {
}
return (
<ThemeProvider value={traceTheme}>
<UIElementsContext.Provider value={UIElements}>
<TracePageHeader
canCollapse={false}
clearSearch={noop}
focusUiFindMatches={noop}
hideMap={false}
hideSummary={false}
nextResult={noop}
onSlimViewClicked={onSlimViewClicked}
onTraceGraphViewClicked={noop}
prevResult={noop}
resultCount={0}
slimView={slim}
textFilter={null}
trace={traceProp}
traceGraphView={false}
updateNextViewRangeTime={updateNextViewRangeTime}
updateViewRangeTime={updateViewRangeTime}
viewRange={viewRange}
searchValue={search}
onSearchValueChange={setSearch}
hideSearchButtons={true}
timeZone={timeZone}
/>
<TraceTimelineViewer
registerAccessors={noop}
scrollToFirstVisibleSpan={noop}
findMatchesIDs={spanFindMatches}
trace={traceProp}
traceTimeline={traceTimeline}
updateNextViewRangeTime={updateNextViewRangeTime}
updateViewRangeTime={updateViewRangeTime}
viewRange={viewRange}
focusSpan={noop}
createLinkToExternalSpan={noop as any}
setSpanNameColumnWidth={setSpanNameColumnWidth}
collapseAll={collapseAll}
collapseOne={collapseOne}
expandAll={expandAll}
expandOne={expandOne}
childrenToggle={childrenToggle}
clearShouldScrollToFirstUiFindMatch={noop}
detailLogItemToggle={detailLogItemToggle}
detailLogsToggle={detailLogsToggle}
detailWarningsToggle={detailWarningsToggle}
detailStackTracesToggle={detailStackTracesToggle}
detailReferencesToggle={detailReferencesToggle}
detailProcessToggle={detailProcessToggle}
detailTagsToggle={detailTagsToggle}
detailToggle={toggleDetail}
setTrace={noop}
addHoverIndentGuideId={addHoverIndentGuideId}
removeHoverIndentGuideId={removeHoverIndentGuideId}
linksGetter={noop as any}
uiFind={search}
createSpanLink={createSpanLink}
scrollElement={props.scrollElement}
/>
</UIElementsContext.Provider>
</ThemeProvider>
<UIElementsContext.Provider value={UIElements}>
<TracePageHeader
canCollapse={false}
clearSearch={noop}
focusUiFindMatches={noop}
hideMap={false}
hideSummary={false}
nextResult={noop}
onSlimViewClicked={onSlimViewClicked}
onTraceGraphViewClicked={noop}
prevResult={noop}
resultCount={0}
slimView={slim}
textFilter={null}
trace={traceProp}
traceGraphView={false}
updateNextViewRangeTime={updateNextViewRangeTime}
updateViewRangeTime={updateViewRangeTime}
viewRange={viewRange}
searchValue={search}
onSearchValueChange={setSearch}
hideSearchButtons={true}
timeZone={timeZone}
/>
<TraceTimelineViewer
registerAccessors={noop}
scrollToFirstVisibleSpan={noop}
findMatchesIDs={spanFindMatches}
trace={traceProp}
traceTimeline={traceTimeline}
updateNextViewRangeTime={updateNextViewRangeTime}
updateViewRangeTime={updateViewRangeTime}
viewRange={viewRange}
focusSpan={noop}
createLinkToExternalSpan={noop as any}
setSpanNameColumnWidth={setSpanNameColumnWidth}
collapseAll={collapseAll}
collapseOne={collapseOne}
expandAll={expandAll}
expandOne={expandOne}
childrenToggle={childrenToggle}
clearShouldScrollToFirstUiFindMatch={noop}
detailLogItemToggle={detailLogItemToggle}
detailLogsToggle={detailLogsToggle}
detailWarningsToggle={detailWarningsToggle}
detailStackTracesToggle={detailStackTracesToggle}
detailReferencesToggle={detailReferencesToggle}
detailProcessToggle={detailProcessToggle}
detailTagsToggle={detailTagsToggle}
detailToggle={toggleDetail}
setTrace={noop}
addHoverIndentGuideId={addHoverIndentGuideId}
removeHoverIndentGuideId={removeHoverIndentGuideId}
linksGetter={noop as any}
uiFind={search}
createSpanLink={createSpanLink}
scrollElement={props.scrollElement}
/>
</UIElementsContext.Provider>
);
}

Loading…
Cancel
Save