Request Timings UI update

The notification banner has been updated (position and style). so it doesn't overlap on Network Panel drawer.
This commit is contained in:
Sudheer Salavadi 2025-04-15 20:20:47 -04:00 committed by Delirium
parent b9e6bd6e72
commit cbb930379d
5 changed files with 119 additions and 40 deletions

View file

@ -137,6 +137,13 @@ function SubHeader(props) {
return (
<>
<WarnBadge
siteId={projectId!}
currentLocation={currentLocation}
version={currentSession?.trackerVersion ?? ''}
containerStyle={{ position: 'relative', left: 0, top: 0, transform: 'none', zIndex: 10 }}
trackerWarnStyle={{ backgroundColor: '#fffbeb' }}
/>
<div
className="w-full px-4 flex items-center border-b relative"
style={{

View file

@ -2,6 +2,7 @@ import React from 'react';
import { Alert } from 'antd';
import { Icon } from 'UI';
import { useTranslation } from 'react-i18next';
import { ArrowUpRight, X } from 'lucide-react';
const localhostWarn = (project: string) => `${project}_localhost_warn`;
@ -29,11 +30,27 @@ function compareVersions(
return VersionComparison.Same;
}
// New optional override props added in WarnBadgeExtraProps
interface WarnBadgeExtraProps {
containerStyle?: React.CSSProperties;
containerClassName?: string;
localhostWarnStyle?: React.CSSProperties;
localhostWarnClassName?: string;
trackerWarnStyle?: React.CSSProperties;
trackerWarnClassName?: string;
}
const WarnBadge = React.memo(
({
currentLocation,
version,
siteId,
containerStyle,
containerClassName,
localhostWarnStyle,
localhostWarnClassName,
trackerWarnStyle,
trackerWarnClassName,
virtualElsFailed,
onVMode,
}: {
@ -42,7 +59,7 @@ const WarnBadge = React.memo(
siteId: string;
virtualElsFailed: boolean;
onVMode: () => void;
}) => {
} & WarnBadgeExtraProps) => {
const { t } = useTranslation();
const localhostWarnSiteKey = localhostWarn(siteId);
const defaultLocalhostWarn =
@ -75,20 +92,37 @@ const WarnBadge = React.memo(
if (!warnings.some(el => el === true)) return null;
// Default container styles and classes
const defaultContainerStyle: React.CSSProperties = {
zIndex: 999,
position: 'absolute',
left: '50%',
bottom: '0',
transform: 'translate(-50%, 80%)',
fontWeight: 500,
};
const defaultContainerClass = "flex flex-col gap-2";
const defaultWarnClass = "px-3 py-.5 border border-gray-lighter shadow-sm rounded bg-active-blue flex items-center justify-between";
// Merge defaults with any overrides
const mergedContainerStyle = { ...defaultContainerStyle, ...containerStyle };
const mergedContainerClassName = containerClassName
? defaultContainerClass + ' ' + containerClassName
: defaultContainerClass;
const mergedLocalhostWarnClassName = localhostWarnClassName
? defaultWarnClass + ' ' + localhostWarnClassName
: defaultWarnClass;
const mergedTrackerWarnClassName = trackerWarnClassName
? defaultWarnClass + ' ' + trackerWarnClassName
: defaultWarnClass;
return (
<div
className="flex flex-col gap-2"
style={{
zIndex: 999,
position: 'absolute',
left: '50%',
bottom: '0',
transform: 'translate(-50%, 80%)',
fontWeight: 500,
}}
className={mergedContainerClassName}
style={mergedContainerStyle}
>
{warnings[0] ? (
<div className="px-3 py-1 border border-gray-lighter drop-shadow-md rounded bg-active-blue flex items-center justify-between">
<div className={mergedLocalhostWarnClassName} style={localhostWarnStyle}>
<div>
<span>{t('Some assets may load incorrectly on localhost.')}</span>
<a
@ -110,25 +144,25 @@ const WarnBadge = React.memo(
</div>
) : null}
{warnings[1] ? (
<div className="px-3 py-1 border border-gray-lighter drop-shadow-md rounded bg-active-blue flex items-center justify-between">
<div>
<div>
{t('Tracker version')}&nbsp;({version})&nbsp;
<div className={mergedTrackerWarnClassName} style={trackerWarnStyle}>
<div className='flex gap-x-2 flex-wrap'>
<div className='font-normal'>
{t('Tracker version')} <span className='mx-1 font-semibold'>{version}</span>
{t('for this recording is')}{' '}
{trackerVerDiff === VersionComparison.Lower
? 'lower '
: 'ahead of '}
{t('the current')}&nbsp;({trackerVersion})&nbsp;{t('version')}.
{t('the current')}<span className='mx-1 font-semibold'>{trackerVersion}</span>{t('version')}.
</div>
<div>
<div className='flex gap-1 items-center font-normal'>
<span>{t('Some recording might display incorrectly.')}</span>
<a
href="https://docs.openreplay.com/en/deployment/upgrade/#tracker-compatibility"
target="_blank"
rel="noreferrer"
className="link ml-1"
className="link ml-1 flex gap-1 items-center"
>
{t('Learn More')}
{t('Learn More')} <ArrowUpRight size={12} />
</a>
</div>
</div>
@ -148,11 +182,26 @@ const WarnBadge = React.memo(
<div className='link' onClick={onVMode}>{t('Enable')}</div>
</div>
<div
className="py-1 ml-3 cursor-pointer"
onClick={() => closeWarning(1)}
>
<X size={18} strokeWidth={1.5} />
</div>
</div>
) : null}
{warnings[2] ? (
<div className="px-3 py-1 border border-gray-lighter drop-shadow-md rounded bg-active-blue flex items-center justify-between">
<div className="flex flex-col">
<div>{t('If you have issues displaying custom HTML elements (i.e when using LWC), consider turning on Virtual Mode.')}</div>
<div className='link' onClick={onVMode}>{t('Enable')}</div>
</div>
<div
className="py-1 ml-3 cursor-pointer"
onClick={() => closeWarning(2)}
>
<Icon name="close" size={16} color="black" />
<X size={18} strokeWidth={1.5} />
</div>
</div>
) : null}

View file

@ -32,36 +32,36 @@ function FetchTimings({ timings }: { timings: Record<string, number> }) {
{
key: 'queueing',
name: 'Queueing',
color: 'bg-[#99a1af]',
color: 'bg-transparent border border-[#666]',
description: 'Time spent in browser queue before connection start',
},
{
key: 'stalled',
name: 'Stalled',
color: 'bg-[#c3c3c3]',
description: 'Time request was stalled after connection start',
},
],
},
{
category: 'Connection Start',
children: [
{
key: 'stalled',
name: 'Stalled',
color: 'bg-[#c3c3c3]',
description: 'Time request was stalled after connection start',
},
{
key: 'dnsLookup',
name: 'DNS Lookup',
color: 'bg-[#00c951]',
color: 'bg-[#12546C]',
description: 'Time spent resolving the DNS',
},
{
key: 'initialConnection',
name: 'Initial Connection',
color: 'bg-[#efb100]',
color: 'bg-[#DD4F18]',
description: 'Time establishing connection (TCP handshakes/retries)',
},
{
key: 'ssl',
name: 'SSL',
color: 'bg-[#ad46ff]',
color: 'bg-[#C079FF]',
description: 'Time spent completing SSL/TLS handshake',
},
],
@ -72,13 +72,13 @@ function FetchTimings({ timings }: { timings: Record<string, number> }) {
{
key: 'ttfb',
name: 'Request & TTFB',
color: 'bg-[#2b7fff]',
color: 'bg-[#3CB347]',
description: 'Time waiting for first byte (server response time)',
},
{
key: 'contentDownload',
name: 'Content Download',
color: 'bg-[#00a63e]',
color: 'bg-[#3E78F7]',
description: 'Time spent receiving the response data',
},
],
@ -116,27 +116,27 @@ function FetchTimings({ timings }: { timings: Record<string, number> }) {
const timelineData = React.useMemo(() => calculateTimelines(), [total]);
return (
<div className="w-full bg-white rounded-lg shadow-sm p-4 font-sans">
<div className="w-full py-4 font-sans">
<div>
<div className="space-y-4">
{timelineData.map((cat, index) => (
<div>
<div>{cat.category}</div>
<div className='text-neutral-500'>{cat.category}</div>
<div>
{cat.children.map((phase, index) => (
<div
key={index}
className="grid grid-cols-12 items-center gap-2 space-y-2"
>
<div className="col-span-4 text-sm text-gray-dark font-medium flex items-center gap-2">
<div className="col-span-4 text-sm text-neutral-950 font-medium flex items-center gap-2">
<Tooltip title={phase.description}>
<HelpCircle size={12} />
</Tooltip>
<span>{phase.name}:</span>
</div>
<div className="col-span-6 relative">
<div className="h-5 bg-gray-lightest rounded overflow-hidden">
<div className="col-span-7 relative">
<div className="h-4 bg-neutral-50 overflow-hidden">
{phase.width > 0 && (
<div
className={`absolute top-0 h-full ${phase.color} hover:opacity-80 transition-opacity`}
@ -150,7 +150,7 @@ function FetchTimings({ timings }: { timings: Record<string, number> }) {
</div>
</div>
<div className="col-span-2 text-right font-mono text-sm text-gray-dark">
<div className="col-span-1 text-right font-mono text-sm text-gray-dark">
{formatTime(phase.duration)}
</div>
</div>
@ -160,11 +160,11 @@ function FetchTimings({ timings }: { timings: Record<string, number> }) {
))}
<div className="grid grid-cols-12 items-center gap-2 pt-2 border-t border-t-gray-light mt-2">
<div className="col-span-3 text-sm text-gray-dark font-semibold">
<div className="col-span-3 text-sm text-neutral-950 font-semibold">
Total:
</div>
<div className="col-span-7"></div>
<div className="col-span-2 text-right font-mono text-sm text-gray-dark font-semibold">
<div className="col-span-2 text-right font-mono text-sm text-neutral-950 font-semibold">
{formatTime(total)}{' '}
{isAdjusted ? (
<span className="ml-1 text-xs text-yellow">

15
frontend/devbox.json Normal file
View file

@ -0,0 +1,15 @@
{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.0/.schema/devbox.schema.json",
"packages": [],
"shell": {
"init_hook": [
"echo 'Welcome to devbox!' > /dev/null"
],
"scripts": {
"test": [
"echo \"Error: no test specified\" && exit 1"
]
}
}
}

8
frontend/devbox.lock Normal file
View file

@ -0,0 +1,8 @@
{
"lockfile_version": "1",
"packages": {
"github:NixOS/nixpkgs/nixpkgs-unstable": {
"resolved": "github:NixOS/nixpkgs/18dd725c29603f582cf1900e0d25f9f1063dbf11?lastModified=1744536153&narHash=sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg%2FN38%3D"
}
}
}