Explore: Unify trace view panel (#70408)

* PanelChrome scales vertically

* Trace View with old Trace View Header works with PanelChrome

* Add top margin

* Remove console.log

* Use contain: 'strict' only when height is passed

* Clean up: use title prop in PanelChrome and everything else should be put under

* Remove test as the title will be passed to PanelChrome

* Remove unused import

* Remove titleWithLinks from PanelChrome

* Make NewTracePageHeader compatible with PanelChrome

* Fix test

* Remove margin

* Remove unused css

* Revert config changes

* Clean up: remove console log and commented out css

* Clean up unused css

* Fix tests

* Revert to a brighter color

* Show links next to duration

* Cleanup

* Remove container style and use default displayMode in PanelChrome

* Clean up

* Revert 'Give feedback' styling

* PanelChrome's width auto scales

* Fix GraphContainer's props

* TraceViewContainer doesn't need a div wrapper

* Remove loading

* Fix build issue

* FIx merge conflict

* Revert old trace page header so the header items shows correctly in dashboards

* Revert to match old trace view header

* Revert NewTracePageHeader so it can show header items in dashboards

* Revert

* Revert tests

* Make 'Give feedback' link aligned vertically

* Remove unused css

* Reduce spacing between title and container in dashboards; remove top padding for NewTracePageHeader

---------

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
This commit is contained in:
Haris Rozajac 2023-07-18 08:15:07 -06:00 committed by GitHub
parent 5f8ace33fb
commit fd01f6cf31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 81 additions and 85 deletions

View File

@ -300,7 +300,18 @@ export const ExamplesHoverHeader = () => {
);
};
export const Basic: StoryFn<typeof PanelChrome> = (args: PanelChromeProps) => {
export const Basic: StoryFn<typeof PanelChrome> = (overrides?: Partial<PanelChromeProps>) => {
const args = {
width: 400,
height: 200,
title: 'Very long title that should get ellipsis when there is no more space',
description,
menu,
children: () => undefined,
};
merge(args, overrides);
const contentStyle = getContentStyle();
return (
@ -345,12 +356,4 @@ Basic.argTypes = {
},
};
Basic.args = {
width: 400,
height: 200,
title: 'Very long title that should get ellipsis when there is no more space',
description,
menu,
};
export default meta;

View File

@ -1,5 +1,6 @@
import { css, cx } from '@emotion/css';
import React, { CSSProperties, ReactElement, ReactNode } from 'react';
import { useMeasure } from 'react-use';
import { GrafanaTheme2, LoadingState } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
@ -20,10 +21,8 @@ import { TitleItem } from './TitleItem';
/**
* @internal
*/
export interface PanelChromeProps {
width: number;
height: number;
children: (innerWidth: number, innerHeight: number) => ReactNode;
export type PanelChromeProps = FixedDimensions | AutoSize;
interface BaseProps {
padding?: PanelPadding;
hoverHeaderOffset?: number;
title?: string;
@ -59,6 +58,18 @@ export interface PanelChromeProps {
onOpenMenu?: () => void;
}
interface FixedDimensions extends BaseProps {
width: number;
height: number;
children: (innerWidth: number, innerHeight: number) => ReactNode;
}
interface AutoSize extends BaseProps {
width?: never;
height?: never;
children: ReactNode;
}
/**
* @internal
*/
@ -98,7 +109,7 @@ export function PanelChrome({
const showOnHoverClass = 'show-on-hover';
const headerHeight = getHeaderHeight(theme, hasHeader);
const { contentStyle, innerWidth, innerHeight } = getContentStyle(padding, theme, width, headerHeight, height);
const { contentStyle, innerWidth, innerHeight } = getContentStyle(padding, theme, headerHeight, height, width);
const headerStyles: CSSProperties = {
height: headerHeight,
@ -111,6 +122,8 @@ export function PanelChrome({
containerStyles.border = 'none';
}
const [ref, { width: loadingBarWidth }] = useMeasure<HTMLDivElement>();
/** Old property name now maps to actions */
if (leftItems) {
actions = leftItems;
@ -130,7 +143,6 @@ export function PanelChrome({
<PanelDescription description={description} className={dragClassCancel} />
{titleItems}
</div>
{loadingState === LoadingState.Streaming && (
<Tooltip content={onCancelQuery ? 'Stop streaming' : 'Streaming'}>
<TitleItem className={dragClassCancel} data-testid="panel-streaming" onClick={onCancelQuery}>
@ -160,9 +172,11 @@ export function PanelChrome({
return (
// tabIndex={0} is needed for keyboard accessibility in the plot area
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
<div className={styles.container} style={containerStyles} data-testid={testid} tabIndex={0}>
<div className={styles.container} style={containerStyles} data-testid={testid} tabIndex={0} ref={ref}>
<div className={styles.loadingBarContainer}>
{loadingState === LoadingState.Loading ? <LoadingBar width={width} ariaLabel="Panel loading bar" /> : null}
{loadingState === LoadingState.Loading ? (
<LoadingBar width={loadingBarWidth} ariaLabel="Panel loading bar" />
) : null}
</div>
{hoverHeader && (
@ -207,8 +221,8 @@ export function PanelChrome({
</div>
)}
<div className={styles.content} style={contentStyle}>
{children(innerWidth, innerHeight)}
<div className={cx(styles.content, height === undefined && styles.containNone)} style={contentStyle}>
{typeof children === 'function' ? children(innerWidth, innerHeight) : children}
</div>
</div>
);
@ -230,22 +244,29 @@ const getHeaderHeight = (theme: GrafanaTheme2, hasHeader: boolean) => {
const getContentStyle = (
padding: string,
theme: GrafanaTheme2,
width: number,
headerHeight: number,
height: number
height?: number,
width?: number
) => {
const chromePadding = (padding === 'md' ? theme.components.panel.padding : 0) * theme.spacing.gridSize;
const panelPadding = chromePadding * 2;
const panelBorder = 1 * 2;
const innerWidth = width - panelPadding - panelBorder;
const innerHeight = height - headerHeight - panelPadding - panelBorder;
let innerWidth = 0;
if (width) {
innerWidth = width - panelPadding - panelBorder;
}
const contentStyle: CSSProperties = {
padding: chromePadding,
};
let innerHeight = 0;
if (height) {
innerHeight = height - headerHeight - panelPadding - panelBorder;
}
return { contentStyle, innerWidth, innerHeight };
};
@ -293,6 +314,9 @@ const getStyles = (theme: GrafanaTheme2) => {
width: '100%',
overflow: 'hidden',
}),
containNone: css({
contain: 'none',
}),
content: css({
label: 'panel-content',
flexGrow: 1,

View File

@ -18,7 +18,9 @@ import { ExploreGraph } from './ExploreGraph';
import { ExploreGraphLabel } from './ExploreGraphLabel';
import { loadGraphStyle } from './utils';
interface Props extends Pick<PanelChromeProps, 'width' | 'height' | 'statusMessage'> {
interface Props extends Pick<PanelChromeProps, 'statusMessage'> {
width: number;
height: number;
data: DataFrame[];
annotations?: DataFrame[];
eventBus: EventBus;

View File

@ -1,9 +1,8 @@
import { css } from '@emotion/css';
import React, { RefObject, useMemo, useState } from 'react';
import { DataFrame, SplitOpen, PanelData, GrafanaTheme2 } from '@grafana/data';
import { DataFrame, PanelData, SplitOpen } from '@grafana/data';
import { config } from '@grafana/runtime';
import { useStyles2 } from '@grafana/ui';
import { PanelChrome } from '@grafana/ui/src/components/PanelChrome/PanelChrome';
import { StoreState, useSelector } from 'app/types';
import { TraceView } from './TraceView';
@ -11,6 +10,7 @@ import TracePageSearchBar from './components/TracePageHeader/SearchBar/TracePage
import { TopOfViewRefType } from './components/TraceTimelineViewer/VirtualizedTraceView';
import { useSearch } from './useSearch';
import { transformDataFrames } from './utils/transform';
interface Props {
dataFrames: DataFrame[];
splitOpenFn: SplitOpen;
@ -20,26 +20,9 @@ interface Props {
topOfViewRef: RefObject<HTMLDivElement>;
}
const getStyles = (theme: GrafanaTheme2) => ({
container: css`
label: container;
margin-bottom: ${theme.spacing(1)};
background-color: ${theme.colors.background.primary};
border: 1px solid ${theme.colors.border.medium};
position: relative;
border-radius: ${theme.shape.radius.default};
width: 100%;
display: flex;
flex-direction: column;
flex: 1 1 0;
padding: ${config.featureToggles.newTraceViewHeader ? 0 : theme.spacing(theme.components.panel.padding)};
`,
});
export function TraceViewContainer(props: Props) {
// At this point we only show single trace
const frame = props.dataFrames[0];
const style = useStyles2(getStyles);
const { dataFrames, splitOpenFn, exploreId, scrollElement, topOfViewRef, queryResponse } = props;
const traceProp = useMemo(() => transformDataFrames(frame), [frame]);
const { search, setSearch, spanFindMatches } = useSearch(traceProp?.spans);
@ -55,20 +38,25 @@ export function TraceViewContainer(props: Props) {
}
return (
<div className={style.container}>
{!config.featureToggles.newTraceViewHeader && (
<TracePageSearchBar
navigable={true}
searchValue={search}
setSearch={setSearch}
spanFindMatches={spanFindMatches}
searchBarSuffix={searchBarSuffix}
setSearchBarSuffix={setSearchBarSuffix}
focusedSpanIdForSearch={focusedSpanIdForSearch}
setFocusedSpanIdForSearch={setFocusedSpanIdForSearch}
datasourceType={datasourceType}
/>
)}
<PanelChrome
padding="none"
title="Trace"
actions={
!config.featureToggles.newTraceViewHeader && (
<TracePageSearchBar
navigable={true}
searchValue={search}
setSearch={setSearch}
spanFindMatches={spanFindMatches}
searchBarSuffix={searchBarSuffix}
setSearchBarSuffix={setSearchBarSuffix}
focusedSpanIdForSearch={focusedSpanIdForSearch}
setFocusedSpanIdForSearch={setFocusedSpanIdForSearch}
datasourceType={datasourceType}
/>
)
}
>
<TraceView
exploreId={exploreId}
dataFrames={dataFrames}
@ -83,6 +71,6 @@ export function TraceViewContainer(props: Props) {
topOfViewRef={topOfViewRef}
topOfViewRefType={TopOfViewRefType.Explore}
/>
</div>
</PanelChrome>
);
}

View File

@ -10,8 +10,6 @@ export const getStyles = (theme: GrafanaTheme2) => {
label: ActionButton;
overflow: hidden;
position: relative;
width: 110px;
justify-content: center;
&:after {
content: '';
background: ${theme.colors.primary.main};
@ -46,6 +44,7 @@ export default function ActionButton(props: ActionButtonProps) {
return (
<Button
className={styles.ActionButton}
size="sm"
variant="secondary"
fill={'outline'}
type="button"

View File

@ -15,8 +15,9 @@ export const getStyles = (theme: GrafanaTheme2) => {
TracePageActions: css`
label: TracePageActions;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
margin-top: 2px;
`,
feedback: css`
margin: 6px;

View File

@ -156,7 +156,6 @@ const getNewStyles = (theme: GrafanaTheme2) => {
header: css`
label: TracePageHeader;
background-color: ${theme.colors.background.primary};
padding: 0.5em 0 0 0;
position: sticky;
top: 0;
z-index: 5;

View File

@ -33,13 +33,8 @@ export const getStyles = (theme: GrafanaTheme2) => {
position: absolute;
top: 0;
right: 0;
z-index: ${theme.zIndex.navbarFixed};
background: ${theme.colors.background.primary};
margin-bottom: -48px;
padding: 8px;
margin-right: 2px;
border-radius: ${theme.shape.radius.default};
box-shadow: ${theme.shadows.z2};
`,
TracePageSearchBarBar: css`
label: TracePageSearchBarBar;
@ -55,17 +50,8 @@ export const getStyles = (theme: GrafanaTheme2) => {
`,
TracePageSearchBarBtn: css`
label: TracePageSearchBarBtn;
transition: 0.2s;
margin-left: 8px;
`,
TracePageSearchBarBtnDisabled: css`
label: TracePageSearchBarBtnDisabled;
opacity: 0.5;
`,
TracePageSearchBarLocateBtn: css`
label: TracePageSearchBarLocateBtn;
padding: 1px 8px 4px;
`,
};
};
@ -101,7 +87,6 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps)
</span>
) : null;
const btnClass = cx(styles.TracePageSearchBarBtn, { [styles.TracePageSearchBarBtnDisabled]: !searchValue });
const SearchBarInputProps = {
className: cx(styles.TracePageSearchBarBar, ubFlexAuto),
name: 'search',
@ -182,7 +167,7 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps)
{navigable && (
<>
<Button
className={btnClass}
className={styles.TracePageSearchBarBtn}
variant="secondary"
disabled={!searchValue}
type="button"
@ -191,7 +176,7 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps)
onClick={nextResult}
/>
<Button
className={btnClass}
className={styles.TracePageSearchBarBtn}
variant="secondary"
disabled={!searchValue}
type="button"

View File

@ -91,11 +91,6 @@ export const getStyles = (theme: GrafanaTheme2) => {
color: unset;
}
`,
TracePageHeaderArchiveIcon: css`
label: TracePageHeaderArchiveIcon;
font-size: 1.78em;
margin-right: 0.15em;
`,
TracePageHeaderTraceId: css`
label: TracePageHeaderTraceId;
white-space: nowrap;