mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: UI improvements to trace view (#34276)
* Various ui fixes * Remove unused classes * Fix opening of collapsible * Fix pointer issue * Update e2e test
This commit is contained in:
parent
3f0df997bc
commit
da1558e7a2
@ -29,7 +29,7 @@ describe('Trace view', () => {
|
|||||||
|
|
||||||
e2e.pages.Explore.General.scrollBar().scrollTo('center');
|
e2e.pages.Explore.General.scrollBar().scrollTo('center');
|
||||||
|
|
||||||
// After scrolling we should have 140 spans instead of the first 100
|
// After scrolling we should have 139 spans instead of the first 100
|
||||||
e2e.components.TraceViewer.spanBar().should('have.length', 140);
|
e2e.components.TraceViewer.spanBar().should('have.length', 139);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -13,6 +13,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
collapseBody: css`
|
collapseBody: css`
|
||||||
label: collapse__body;
|
label: collapse__body;
|
||||||
padding: ${theme.spacing(theme.components.panel.padding)};
|
padding: ${theme.spacing(theme.components.panel.padding)};
|
||||||
|
padding-top: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -59,7 +60,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
`,
|
`,
|
||||||
header: css`
|
header: css`
|
||||||
label: collapse__header;
|
label: collapse__header;
|
||||||
padding: ${theme.spacing(1, 2)};
|
padding: ${theme.spacing(1, 2, 0.5, 2)};
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
transition: all 0.1s linear;
|
transition: all 0.1s linear;
|
||||||
@ -67,20 +68,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
`,
|
`,
|
||||||
headerCollapsed: css`
|
headerCollapsed: css`
|
||||||
label: collapse__header--collapsed;
|
label: collapse__header--collapsed;
|
||||||
cursor: pointer;
|
padding: ${theme.spacing(1, 2, 0.5, 2)};
|
||||||
padding: ${theme.spacing(1, 2)};
|
|
||||||
`,
|
|
||||||
headerButtons: css`
|
|
||||||
label: collapse__header-buttons;
|
|
||||||
margin-right: ${theme.spacing(1)};
|
|
||||||
margin-top: ${theme.spacing(0.25)};
|
|
||||||
font-size: ${theme.typography.size.lg};
|
|
||||||
line-height: ${theme.typography.h6.lineHeight};
|
|
||||||
display: inherit;
|
|
||||||
`,
|
|
||||||
headerButtonsCollapsed: css`
|
|
||||||
label: collapse__header-buttons--collapsed;
|
|
||||||
display: none;
|
|
||||||
`,
|
`,
|
||||||
headerLabel: css`
|
headerLabel: css`
|
||||||
label: collapse__header-label;
|
label: collapse__header-label;
|
||||||
@ -110,6 +98,7 @@ export const ControlledCollapse: FunctionComponent<Props> = ({ isOpen, onToggle,
|
|||||||
return (
|
return (
|
||||||
<Collapse
|
<Collapse
|
||||||
isOpen={open}
|
isOpen={open}
|
||||||
|
collapsible
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onToggle={() => {
|
onToggle={() => {
|
||||||
setOpen(!open);
|
setOpen(!open);
|
||||||
@ -140,14 +129,11 @@ export const Collapse: FunctionComponent<Props> = ({
|
|||||||
const panelClass = cx([style.collapse, 'panel-container', className]);
|
const panelClass = cx([style.collapse, 'panel-container', className]);
|
||||||
const loaderClass = loading ? cx([style.loader, style.loaderActive]) : cx([style.loader]);
|
const loaderClass = loading ? cx([style.loader, style.loaderActive]) : cx([style.loader]);
|
||||||
const headerClass = collapsible ? cx([style.header]) : cx([style.headerCollapsed]);
|
const headerClass = collapsible ? cx([style.header]) : cx([style.headerCollapsed]);
|
||||||
const headerButtonsClass = collapsible ? cx([style.headerButtons]) : cx([style.headerButtonsCollapsed]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={panelClass}>
|
<div className={panelClass}>
|
||||||
<div className={headerClass} onClick={onClickToggle}>
|
<div className={headerClass} onClick={onClickToggle}>
|
||||||
<div className={headerButtonsClass}>
|
{collapsible && <Icon name={isOpen ? 'angle-up' : 'angle-down'} />}
|
||||||
<Icon name={isOpen ? 'angle-up' : 'angle-down'} />
|
|
||||||
</div>
|
|
||||||
<div className={cx([style.headerLabel])}>{label}</div>
|
<div className={cx([style.headerLabel])}>{label}</div>
|
||||||
</div>
|
</div>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
|
@ -100,7 +100,7 @@ const getStyles = createStyle((theme: Theme) => {
|
|||||||
font-size: 1.7em;
|
font-size: 1.7em;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
margin: 0 0 0 0.5em;
|
margin: 0 0 0 0.5em;
|
||||||
padding: 0.5em 0;
|
padding-bottom: 0.5em;
|
||||||
`,
|
`,
|
||||||
TracePageHeaderTitleCollapsible: css`
|
TracePageHeaderTitleCollapsible: css`
|
||||||
label: TracePageHeaderTitleCollapsible;
|
label: TracePageHeaderTitleCollapsible;
|
||||||
|
@ -42,7 +42,6 @@ const getStyles = createStyle((theme: Theme) => {
|
|||||||
return {
|
return {
|
||||||
nameWrapper: css`
|
nameWrapper: css`
|
||||||
label: nameWrapper;
|
label: nameWrapper;
|
||||||
background: ${autoColor(theme, '#f8f8f8')};
|
|
||||||
line-height: 27px;
|
line-height: 27px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -58,7 +58,7 @@ const getStyles = createStyle((theme: Theme) => {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
infoWrapper: css`
|
infoWrapper: css`
|
||||||
background: ${autoColor(theme, '#f5f5f5')};
|
label: infoWrapper;
|
||||||
border: 1px solid ${autoColor(theme, '#d3d3d3')};
|
border: 1px solid ${autoColor(theme, '#d3d3d3')};
|
||||||
border-top: 3px solid;
|
border-top: 3px solid;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
@ -123,7 +123,7 @@ export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProp
|
|||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
return (
|
return (
|
||||||
<TimelineRow>
|
<TimelineRow>
|
||||||
<TimelineRow.Cell width={columnDivision}>
|
<TimelineRow.Cell width={columnDivision} style={{ overflow: 'hidden' }}>
|
||||||
<SpanTreeOffset
|
<SpanTreeOffset
|
||||||
span={span}
|
span={span}
|
||||||
showChildrenIcon={false}
|
showChildrenIcon={false}
|
||||||
|
@ -34,7 +34,6 @@ export const getStyles = createStyle((theme: Theme) => {
|
|||||||
SpanTreeOffsetParent: css`
|
SpanTreeOffsetParent: css`
|
||||||
label: SpanTreeOffsetParent;
|
label: SpanTreeOffsetParent;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: ${autoColor(theme, '#e8e8e8')};
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
@ -34,12 +34,12 @@ import { StoreState } from 'app/types';
|
|||||||
import { ExploreToolbar } from './ExploreToolbar';
|
import { ExploreToolbar } from './ExploreToolbar';
|
||||||
import { NoDataSourceCallToAction } from './NoDataSourceCallToAction';
|
import { NoDataSourceCallToAction } from './NoDataSourceCallToAction';
|
||||||
import { getTimeZone } from '../profile/state/selectors';
|
import { getTimeZone } from '../profile/state/selectors';
|
||||||
import { TraceView } from './TraceView/TraceView';
|
|
||||||
import { SecondaryActions } from './SecondaryActions';
|
import { SecondaryActions } from './SecondaryActions';
|
||||||
import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, FilterItem } from '@grafana/ui/src/components/Table/types';
|
import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, FilterItem } from '@grafana/ui/src/components/Table/types';
|
||||||
import { ExploreGraphNGPanel } from './ExploreGraphNGPanel';
|
import { ExploreGraphNGPanel } from './ExploreGraphNGPanel';
|
||||||
import { NodeGraphContainer } from './NodeGraphContainer';
|
import { NodeGraphContainer } from './NodeGraphContainer';
|
||||||
import { ResponseErrorContainer } from './ResponseErrorContainer';
|
import { ResponseErrorContainer } from './ResponseErrorContainer';
|
||||||
|
import { TraceViewContainer } from './TraceView/TraceViewContainer';
|
||||||
|
|
||||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||||
return {
|
return {
|
||||||
@ -290,7 +290,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
// If there is no data (like 404) we show a separate error so no need to show anything here
|
// If there is no data (like 404) we show a separate error so no need to show anything here
|
||||||
dataFrames.length && <TraceView exploreId={exploreId} dataFrames={dataFrames} splitOpenFn={splitOpen} />
|
dataFrames.length && <TraceViewContainer exploreId={exploreId} dataFrames={dataFrames} splitOpenFn={splitOpen} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Badge, Collapse } from '@grafana/ui';
|
import { Badge, Collapse } from '@grafana/ui';
|
||||||
import { DataFrame, TimeRange } from '@grafana/data';
|
import { DataFrame, TimeRange } from '@grafana/data';
|
||||||
import { ExploreId, StoreState } from '../../types';
|
import { ExploreId, StoreState } from '../../types';
|
||||||
@ -19,19 +19,23 @@ export function UnconnectedNodeGraphContainer(props: Props & ConnectedProps<type
|
|||||||
const { dataFrames, range, splitOpen, short } = props;
|
const { dataFrames, range, splitOpen, short } = props;
|
||||||
const getLinks = useLinks(range, splitOpen);
|
const getLinks = useLinks(range, splitOpen);
|
||||||
|
|
||||||
|
const [open, setOpen] = useState(true);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: short ? 300 : 600 }}>
|
<Collapse
|
||||||
<Collapse
|
label={
|
||||||
label={
|
<span>
|
||||||
<span>
|
Node graph <Badge text={'Beta'} color={'blue'} icon={'rocket'} tooltip={'This visualization is in beta'} />
|
||||||
Node graph <Badge text={'Beta'} color={'blue'} icon={'rocket'} tooltip={'This visualization is in beta'} />
|
</span>
|
||||||
</span>
|
}
|
||||||
}
|
collapsible={short}
|
||||||
isOpen
|
isOpen={short ? open : true}
|
||||||
>
|
onToggle={short ? () => setOpen(!open) : undefined}
|
||||||
|
>
|
||||||
|
<div style={{ height: short ? 300 : 600 }}>
|
||||||
<NodeGraph dataFrames={dataFrames} getLinks={getLinks} />
|
<NodeGraph dataFrames={dataFrames} getLinks={getLinks} />
|
||||||
</Collapse>
|
</div>
|
||||||
</div>
|
</Collapse>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
public/app/features/explore/TraceView/TraceViewContainer.tsx
Normal file
20
public/app/features/explore/TraceView/TraceViewContainer.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Collapse } from '@grafana/ui';
|
||||||
|
import { DataFrame } from '@grafana/data';
|
||||||
|
import { TraceView } from './TraceView';
|
||||||
|
import { ExploreId, SplitOpen } from '../../../types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
dataFrames: DataFrame[];
|
||||||
|
splitOpenFn: SplitOpen;
|
||||||
|
exploreId: ExploreId;
|
||||||
|
}
|
||||||
|
export function TraceViewContainer(props: Props) {
|
||||||
|
const { dataFrames, splitOpenFn, exploreId } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapse label="Trace View" isOpen>
|
||||||
|
<TraceView exploreId={exploreId} dataFrames={dataFrames} splitOpenFn={splitOpenFn} />
|
||||||
|
</Collapse>
|
||||||
|
);
|
||||||
|
}
|
@ -12,6 +12,11 @@ function getStyles() {
|
|||||||
label: LegendItem;
|
label: LegendItem;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
`,
|
`,
|
||||||
|
|
||||||
|
legend: css`
|
||||||
|
label: Legend;
|
||||||
|
pointer-events: all;
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +46,7 @@ export const Legend = function Legend(props: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VizLegend<ItemData>
|
<VizLegend<ItemData>
|
||||||
|
className={styles.legend}
|
||||||
displayMode={LegendDisplayMode.List}
|
displayMode={LegendDisplayMode.List}
|
||||||
placement={'bottom'}
|
placement={'bottom'}
|
||||||
items={colorItems}
|
items={colorItems}
|
||||||
|
@ -58,6 +58,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
pointer-events: none;
|
||||||
`,
|
`,
|
||||||
legend: css`
|
legend: css`
|
||||||
label: legend;
|
label: legend;
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Button, HorizontalGroup, VerticalGroup } from '@grafana/ui';
|
import { Button, HorizontalGroup, useStyles, VerticalGroup } from '@grafana/ui';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
|
||||||
|
function getStyles() {
|
||||||
|
return {
|
||||||
|
wrapper: css`
|
||||||
|
label: wrapper;
|
||||||
|
pointer-events: all;
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface Props<Config> {
|
interface Props<Config> {
|
||||||
config: Config;
|
config: Config;
|
||||||
@ -20,9 +30,10 @@ export function ViewControls<Config extends Record<string, any>>(props: Props<Co
|
|||||||
|
|
||||||
// For debugging the layout, should be removed here and maybe moved to panel config later on
|
// For debugging the layout, should be removed here and maybe moved to panel config later on
|
||||||
const allowConfiguration = false;
|
const allowConfiguration = false;
|
||||||
|
const styles = useStyles(getStyles);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={styles.wrapper}>
|
||||||
<VerticalGroup spacing="sm">
|
<VerticalGroup spacing="sm">
|
||||||
<HorizontalGroup spacing="xs">
|
<HorizontalGroup spacing="xs">
|
||||||
<Button
|
<Button
|
||||||
|
Loading…
Reference in New Issue
Block a user