diff --git a/src/components/view/http/http-performance-card.tsx b/src/components/view/http/http-performance-card.tsx index 9ec10940..70e24ed1 100644 --- a/src/components/view/http/http-performance-card.tsx +++ b/src/components/view/http/http-performance-card.tsx @@ -5,7 +5,6 @@ import { get } from 'typesafe-get'; import { styled } from '../../../styles'; import { - Omit, HttpExchange, TimingEvents, ExchangeMessage @@ -14,7 +13,7 @@ import { asHeaderArray, joinAnd } from '../../../util'; import { Icon, WarningIcon, SuggestionIcon } from '../../../icons'; import { AccountStore } from '../../../model/account/account-store'; -import { getReadableSize, testEncodings } from '../../../model/events/bodies'; +import {getReadableDuration, getReadableSize, testEncodings} from '../../../model/events/bodies'; import { explainCacheability, explainCacheLifetime, @@ -41,10 +40,6 @@ interface HttpPerformanceCardProps extends CollapsibleCardProps { accountStore?: AccountStore; } -function sigFig(num: number, figs: number): number { - return parseFloat(num.toFixed(figs)); -} - const TimingPill = observer((p: { className?: string, timingEvents: TimingEvents }) => { // We can't show timing info if the request is still going const doneTimestamp = p.timingEvents.responseSentTimestamp || p.timingEvents.abortedTimestamp; @@ -52,12 +47,7 @@ const TimingPill = observer((p: { className?: string, timingEvents: TimingEvents const durationMs = doneTimestamp - p.timingEvents.startTimestamp; - return { - durationMs < 100 ? sigFig(durationMs, 2) + 'ms' : // 22.34ms - durationMs < 1000 ? sigFig(durationMs, 1) + 'ms' : // 999.5ms - durationMs < 10000 ? sigFig(durationMs / 1000, 3) + ' seconds' : // 3.045 seconds - sigFig(durationMs / 1000, 1) + ' seconds' // 11.2 seconds - }; + return {getReadableDuration(durationMs)}; }); export const HttpPerformanceCard = inject('accountStore')(observer((props: HttpPerformanceCardProps) => { @@ -342,4 +332,4 @@ const CachingPerformance = observer((p: { exchange: HttpExchange }) => { ) } ; -}); \ No newline at end of file +}); diff --git a/src/components/view/view-event-list.tsx b/src/components/view/view-event-list.tsx index 9b197f3d..d11195a3 100644 --- a/src/components/view/view-event-list.tsx +++ b/src/components/view/view-event-list.tsx @@ -23,7 +23,11 @@ import { } from '../../model/events/categorization'; import { UnreachableCheck } from '../../util/error'; -import { getReadableSize } from '../../model/events/bodies'; +import { + getReadableSize, + getReadableDuration +} from '../../model/events/bodies'; + import { filterProps } from '../component-utils'; import { EmptyState } from '../common/empty-state'; @@ -166,6 +170,18 @@ const PathAndQuery = styled(Column)` flex-basis: 1000px; `; +const Duration = styled(Column)` + flex-basis: 80px; + flex-shrink: 0; + flex-grow: 0; +`; + +const Size = styled(Column)` + flex-basis: 80px; + flex-shrink: 0; + flex-grow: 0; +`; + // Match Method + Status, but shrink right margin slightly so that // spinner + "WebRTC Media" fits OK. const EventTypeColumn = styled(Column)` @@ -372,6 +388,10 @@ const ExchangeRow = observer(({ category } = exchange; + let durationMs = ('startTime' in exchange.timingEvents) ? ( + (exchange.timingEvents.responseSentTimestamp || exchange.timingEvents.abortedTimestamp || 0) - exchange.timingEvents.startTimestamp + ) : 0; + return { request.parsedUrl.pathname + request.parsedUrl.search } + + {durationMs > 0 ? getReadableDuration(durationMs) : ''} + + + { exchange.isSuccessfulExchange() ? getReadableSize(exchange.response.body.encoded.byteLength) : ''} + ; }); @@ -666,6 +692,8 @@ export class ViewEventList extends React.Component { Source Host Path and query + Duration + Size { @@ -869,4 +897,4 @@ export class ViewEventList extends React.Component { event.preventDefault(); } -} \ No newline at end of file +} diff --git a/src/model/events/bodies.ts b/src/model/events/bodies.ts index 36bf7fca..e4020a45 100644 --- a/src/model/events/bodies.ts +++ b/src/model/events/bodies.ts @@ -18,6 +18,17 @@ export function getReadableSize(bytes: number, siUnits = true) { return (bytes / Math.pow(thresh, unitIndex)).toFixed(1).replace(/\.0$/, '') + ' ' + unitName; } +function sigFig(num: number, figs: number): number { + return parseFloat(num.toFixed(figs)); +} + +export function getReadableDuration(durationMs: number): string { + return (durationMs < 100) ? (sigFig(durationMs, 2) + 'ms') // 22.34ms + : (durationMs < 1000 ? sigFig(durationMs, 1) + 'ms' // 999.5ms + : (durationMs < 10000 ? sigFig(durationMs / 1000, 3) + ' s' // 3.045 seconds + : sigFig(durationMs / 1000, 1) + ' s')) // 11.2 seconds +} + const EncodedSizesCacheKey = Symbol('encoded-body-test'); type EncodedBodySizes = { [encoding: string]: number }; type EncodedSizesCache = Map