Submit
Path:
~
/
/
usr
/
share
/
grafana
/
public
/
app
/
features
/
explore
/
TraceView
/
components
/
TracePageHeader
/
File Content:
TracePageHeader.tsx
// Copyright (c) 2017 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { css } from '@emotion/css'; import cx from 'classnames'; import React, { memo, useEffect, useMemo } from 'react'; import { CoreApp, DataFrame, dateTimeFormat, GrafanaTheme2 } from '@grafana/data'; import { TimeZone } from '@grafana/schema'; import { Badge, BadgeColor, Tooltip, useStyles2 } from '@grafana/ui'; import { SearchProps } from '../../useSearch'; import ExternalLinks from '../common/ExternalLinks'; import TraceName from '../common/TraceName'; import { getTraceLinks } from '../model/link-patterns'; import { getHeaderTags, getTraceName } from '../model/trace-viewer'; import { Trace } from '../types'; import { formatDuration } from '../utils/date'; import TracePageActions from './Actions/TracePageActions'; import { SpanFilters } from './SpanFilters/SpanFilters'; export type TracePageHeaderProps = { trace: Trace | null; data: DataFrame; app?: CoreApp; timeZone: TimeZone; search: SearchProps; setSearch: React.Dispatch<React.SetStateAction<SearchProps>>; showSpanFilters: boolean; setShowSpanFilters: (isOpen: boolean) => void; showSpanFilterMatchesOnly: boolean; setShowSpanFilterMatchesOnly: (showMatchesOnly: boolean) => void; showCriticalPathSpansOnly: boolean; setShowCriticalPathSpansOnly: (showCriticalPathSpansOnly: boolean) => void; setFocusedSpanIdForSearch: React.Dispatch<React.SetStateAction<string>>; spanFilterMatches: Set<string> | undefined; datasourceType: string; setHeaderHeight: (height: number) => void; }; export const TracePageHeader = memo((props: TracePageHeaderProps) => { const { trace, data, app, timeZone, search, setSearch, showSpanFilters, setShowSpanFilters, showSpanFilterMatchesOnly, setShowSpanFilterMatchesOnly, showCriticalPathSpansOnly, setShowCriticalPathSpansOnly, setFocusedSpanIdForSearch, spanFilterMatches, datasourceType, setHeaderHeight, } = props; const styles = useStyles2(getNewStyles); useEffect(() => { setHeaderHeight(document.querySelector('.' + styles.header)?.scrollHeight ?? 0); }, [setHeaderHeight, showSpanFilters, styles.header]); const links = useMemo(() => { if (!trace) { return []; } return getTraceLinks(trace); }, [trace]); if (!trace) { return null; } const timestamp = (trace: Trace, timeZone: TimeZone) => { // Convert date from micro to milli seconds const dateStr = dateTimeFormat(trace.startTime / 1000, { timeZone, defaultWithMS: true }); const match = dateStr.match(/^(.+)(:\d\d\.\d+)$/); return match ? ( <span className={styles.TracePageHeaderOverviewItemValue}> {match[1]} <span className={styles.TracePageHeaderOverviewItemValueDetail}>{match[2]}</span> </span> ) : ( dateStr ); }; const title = ( <h1 className={cx(styles.title)}> <TraceName traceName={getTraceName(trace.spans)} /> <small className={styles.duration}>{formatDuration(trace.duration)}</small> </h1> ); const { method, status, url } = getHeaderTags(trace.spans); let statusColor: BadgeColor = 'green'; if (status && status.length > 0) { if (status[0].value.toString().charAt(0) === '4') { statusColor = 'orange'; } else if (status[0].value.toString().charAt(0) === '5') { statusColor = 'red'; } } return ( <header className={styles.header}> <div className={styles.titleRow}> {links && links.length > 0 && <ExternalLinks links={links} className={styles.TracePageHeaderBack} />} {title} <TracePageActions traceId={trace.traceID} data={data} app={app} /> </div> <div className={styles.subtitle}> <span className={styles.timestamp}>{timestamp(trace, timeZone)}</span> <span className={styles.tagMeta}> {method && method.length > 0 && ( <Tooltip content={'http.method'} interactive={true}> <span className={styles.tag}> <Badge text={method[0].value} color="blue" /> </span> </Tooltip> )} {status && status.length > 0 && ( <Tooltip content={'http.status_code'} interactive={true}> <span className={styles.tag}> <Badge text={status[0].value} color={statusColor} /> </span> </Tooltip> )} {url && url.length > 0 && ( <Tooltip content={'http.url or http.target or http.path'} interactive={true}> <span className={styles.url}>{url[0].value}</span> </Tooltip> )} </span> </div> <SpanFilters trace={trace} showSpanFilters={showSpanFilters} setShowSpanFilters={setShowSpanFilters} showSpanFilterMatchesOnly={showSpanFilterMatchesOnly} setShowSpanFilterMatchesOnly={setShowSpanFilterMatchesOnly} showCriticalPathSpansOnly={showCriticalPathSpansOnly} setShowCriticalPathSpansOnly={setShowCriticalPathSpansOnly} search={search} setSearch={setSearch} spanFilterMatches={spanFilterMatches} setFocusedSpanIdForSearch={setFocusedSpanIdForSearch} datasourceType={datasourceType} /> </header> ); }); TracePageHeader.displayName = 'TracePageHeader'; const getNewStyles = (theme: GrafanaTheme2) => { return { TracePageHeaderBack: css` label: TracePageHeaderBack; align-items: center; align-self: stretch; background-color: #fafafa; border-bottom: 1px solid #ddd; border-right: 1px solid #ddd; color: inherit; display: flex; font-size: 1.4rem; padding: 0 1rem; margin-bottom: -1px; &:hover { background-color: #f0f0f0; border-color: #ccc; } `, TracePageHeaderOverviewItemValueDetail: cx( css` label: TracePageHeaderOverviewItemValueDetail; color: #aaa; `, 'trace-item-value-detail' ), TracePageHeaderOverviewItemValue: css` label: TracePageHeaderOverviewItemValue; &:hover > .trace-item-value-detail { color: unset; } `, header: css` label: TracePageHeader; background-color: ${theme.colors.background.primary}; padding: 0.5em 0 0 0; position: sticky; top: 0; z-index: 5; `, titleRow: css` align-items: flex-start; display: flex; padding: 0 8px; `, title: css` color: inherit; flex: 1; font-size: 1.7em; line-height: 1em; `, subtitle: css` flex: 1; line-height: 1em; margin: -0.5em 0.5em 0.75em 0.5em; `, tag: css` margin: 0 0.5em 0 0; `, duration: css` color: #aaa; margin: 0 0.75em; `, timestamp: css` vertical-align: middle; `, tagMeta: css` margin: 0 0.75em; vertical-align: text-top; `, url: css` margin: -2.5px 0.3em; height: 15px; overflow: hidden; word-break: break-all; line-height: 20px; `, TracePageHeaderTraceId: css` label: TracePageHeaderTraceId; white-space: nowrap; text-overflow: ellipsis; max-width: 30%; display: inline-block; `, }; };
Submit
FILE
FOLDER
INFO
Name
Size
Permission
Action
Actions
---
0755
SearchBar
---
0755
SpanFilters
---
0755
SpanGraph
---
0755
TracePageHeader.test.tsx
5084 bytes
0644
TracePageHeader.tsx
7853 bytes
0644
index.tsx
654 bytes
0644
N4ST4R_ID | Naxtarrr