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:
parent
b9e6bd6e72
commit
cbb930379d
5 changed files with 119 additions and 40 deletions
|
|
@ -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={{
|
||||
|
|
|
|||
|
|
@ -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')} ({version})
|
||||
<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')} ({trackerVersion}) {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}
|
||||
|
|
|
|||
|
|
@ -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
15
frontend/devbox.json
Normal 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
8
frontend/devbox.lock
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue