1// Copyright (c) 2017 Uber Technologies, Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import * as React from 'react'; 16import { sortBy as _sortBy } from 'lodash'; 17import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down'; 18import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right'; 19import { css } from '@emotion/css'; 20 21import AccordianKeyValues from './AccordianKeyValues'; 22import { formatDuration } from '../utils'; 23import { TNil } from '../../types'; 24import { TraceLog, TraceKeyValuePair, TraceLink } from '../../types/trace'; 25import { autoColor, createStyle, Theme, useTheme } from '../../Theme'; 26import { uAlignIcon, ubMb1 } from '../../uberUtilityStyles'; 27 28const getStyles = createStyle((theme: Theme) => { 29 return { 30 AccordianLogs: css` 31 label: AccordianLogs; 32 border: 1px solid ${autoColor(theme, '#d8d8d8')}; 33 position: relative; 34 margin-bottom: 0.25rem; 35 `, 36 AccordianLogsHeader: css` 37 label: AccordianLogsHeader; 38 background: ${autoColor(theme, '#e4e4e4')}; 39 color: inherit; 40 display: block; 41 padding: 0.25rem 0.5rem; 42 &:hover { 43 background: ${autoColor(theme, '#dadada')}; 44 } 45 `, 46 AccordianLogsContent: css` 47 label: AccordianLogsContent; 48 background: ${autoColor(theme, '#f0f0f0')}; 49 border-top: 1px solid ${autoColor(theme, '#d8d8d8')}; 50 padding: 0.5rem 0.5rem 0.25rem 0.5rem; 51 `, 52 AccordianLogsFooter: css` 53 label: AccordianLogsFooter; 54 color: ${autoColor(theme, '#999')}; 55 `, 56 }; 57}); 58 59type AccordianLogsProps = { 60 interactive?: boolean; 61 isOpen: boolean; 62 linksGetter: ((pairs: TraceKeyValuePair[], index: number) => TraceLink[]) | TNil; 63 logs: TraceLog[]; 64 onItemToggle?: (log: TraceLog) => void; 65 onToggle?: () => void; 66 openedItems?: Set<TraceLog>; 67 timestamp: number; 68}; 69 70export default function AccordianLogs(props: AccordianLogsProps) { 71 const { interactive, isOpen, linksGetter, logs, openedItems, onItemToggle, onToggle, timestamp } = props; 72 let arrow: React.ReactNode | null = null; 73 let HeaderComponent: 'span' | 'a' = 'span'; 74 let headerProps: {} | null = null; 75 if (interactive) { 76 arrow = isOpen ? <IoIosArrowDown className={uAlignIcon} /> : <IoIosArrowRight className="u-align-icon" />; 77 HeaderComponent = 'a'; 78 headerProps = { 79 'aria-checked': isOpen, 80 onClick: onToggle, 81 role: 'switch', 82 }; 83 } 84 85 const styles = getStyles(useTheme()); 86 return ( 87 <div className={styles.AccordianLogs}> 88 <HeaderComponent className={styles.AccordianLogsHeader} {...headerProps}> 89 {arrow} <strong>Logs</strong> ({logs.length}) 90 </HeaderComponent> 91 {isOpen && ( 92 <div className={styles.AccordianLogsContent}> 93 {_sortBy(logs, 'timestamp').map((log, i) => ( 94 <AccordianKeyValues 95 // `i` is necessary in the key because timestamps can repeat 96 key={`${log.timestamp}-${i}`} 97 className={i < logs.length - 1 ? ubMb1 : null} 98 data={log.fields || []} 99 highContrast 100 interactive={interactive} 101 isOpen={openedItems ? openedItems.has(log) : false} 102 label={`${formatDuration(log.timestamp - timestamp)}`} 103 linksGetter={linksGetter} 104 onToggle={interactive && onItemToggle ? () => onItemToggle(log) : null} 105 /> 106 ))} 107 <small className={styles.AccordianLogsFooter}> 108 Log timestamps are relative to the start time of the full trace. 109 </small> 110 </div> 111 )} 112 </div> 113 ); 114} 115 116AccordianLogs.defaultProps = { 117 interactive: true, 118 linksGetter: undefined, 119 onItemToggle: undefined, 120 onToggle: undefined, 121 openedItems: undefined, 122}; 123