UI patch 4 (#2572)

* ui: spot related fixes

* ui: remove random logs

* ui: fix insights mapping

* ui: hide doc link for spot stuff

* ui: force worker for hls
This commit is contained in:
Delirium 2024-09-13 14:37:20 +02:00 committed by GitHub
parent 5e1d895ce6
commit e196643c8f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 74 additions and 68 deletions

View file

@ -16,7 +16,6 @@ function WidgetOptions(props: Props) {
const metric: any = metricStore.instance;
const handleChange = (value: any) => {
console.log(`selected ${value}`);
metric.update({ metricFormat: value });
};

View file

@ -157,7 +157,6 @@ function EventsBlock(props: IProps) {
React.useEffect(() => {
if (scroller.current) {
if (!mouseOver) {
console.log('scrolling to index', currentTimeEventIndex, scroller.current);
scroller.current.scrollToIndex(currentTimeEventIndex, { align: 'center' });
}
}

View file

@ -24,6 +24,7 @@ function SpotNetwork({ panelHeight, onClose }: { panelHeight: number, onClose: (
resourceListNow={[]}
websocketList={[]}
websocketListNow={[]}
isSpot
/* @ts-ignore */
player={{ jump: (t) => spotPlayerStore.setTime(t) }}
activeOutsideIndex={index}

View file

@ -1,8 +1,9 @@
import { InfoCircleOutlined, PlayCircleOutlined } from '@ant-design/icons';
import { Alert, Button } from 'antd';
import Hls from 'hls.js';
import { observer } from 'mobx-react-lite';
import React from 'react';
import {Alert, Button} from 'antd';
import {PlayCircleOutlined, InfoCircleOutlined} from '@ant-design/icons';
import spotPlayerStore from '../spotPlayerStore';
const base64toblob = (str: string) => {
@ -33,7 +34,9 @@ function SpotVideoContainer({
checkReady: () => Promise<boolean>;
}) {
const [prevIsProcessing, setPrevIsProcessing] = React.useState(false);
const [processingState, setProcessingState] = React.useState<ProcessingState>(ProcessingState.Unchecked);
const [processingState, setProcessingState] = React.useState<ProcessingState>(
ProcessingState.Unchecked
);
const [isLoaded, setLoaded] = React.useState(false);
const videoRef = React.useRef<HTMLVideoElement>(null);
const playbackTime = React.useRef(0);
@ -69,13 +72,15 @@ function SpotVideoContainer({
clearInterval(int);
}
});
}, 5000)
}, 5000);
} else {
setProcessingState(ProcessingState.Ready);
}
import('hls.js').then(({ default: Hls }) => {
if (Hls.isSupported() && videoRef.current) {
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
const isSafari = /^((?!chrome|android).)*safari/i.test(
navigator.userAgent
);
if (isSafari) {
setLoaded(true);
} else {
@ -85,9 +90,7 @@ function SpotVideoContainer({
}
if (streamFile) {
const hls = new Hls({
// not needed for small videos (we have 3 min limit and 720 quality with half kbps)
enableWorker: false,
// = 1MB, should be enough
enableWorker: true,
maxBufferSize: 1000 * 1000,
});
const url = URL.createObjectURL(base64toblob(streamFile));
@ -124,7 +127,11 @@ function SpotVideoContainer({
};
check();
}
} else if (streamFile && videoRef.current && videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
} else if (
streamFile &&
videoRef.current &&
videoRef.current.canPlayType('application/vnd.apple.mpegurl')
) {
setLoaded(true);
videoRef.current.src = URL.createObjectURL(base64toblob(streamFile));
startPlaying();
@ -185,40 +192,44 @@ function SpotVideoContainer({
}
}, [spotPlayerStore.playbackRate]);
const reloadPage = () => { window.location.reload(); };
const reloadPage = () => {
window.location.reload();
};
return (
<>
<div className="absolute z-20 left-2/4 -top-6" style={{ transform: 'translate(-50%, 0)' }}>
{processingState === ProcessingState.Processing ? (
<Alert
className='trimIsProcessing rounded-lg shadow-sm border-indigo-500 bg-indigo-50'
message="Youre viewing the original recording. Processed Spot will be available here shortly."
showIcon
type="info"
icon={<InfoCircleOutlined style={{ color: '#394dfe' }} />}
/>
) : prevIsProcessing ? (
<Alert
className='trimIsReady rounded-lg shadow-sm border-0'
message="Your processed Spot is ready!"
showIcon
type="success"
action={
<Button
size="small"
type="default"
icon={<PlayCircleOutlined />}
onClick={reloadPage}
className='ml-2'
>
Play Now
</Button>
}
/>
) : null}
</div>
<div
className="absolute z-20 left-2/4 -top-6"
style={{ transform: 'translate(-50%, 0)' }}
>
{processingState === ProcessingState.Processing ? (
<Alert
className="trimIsProcessing rounded-lg shadow-sm border-indigo-500 bg-indigo-50"
message="Youre viewing the original recording. Processed Spot will be available here shortly."
showIcon
type="info"
icon={<InfoCircleOutlined style={{ color: '#394dfe' }} />}
/>
) : prevIsProcessing ? (
<Alert
className="trimIsReady rounded-lg shadow-sm border-0"
message="Your processed Spot is ready!"
showIcon
type="success"
action={
<Button
size="small"
type="default"
icon={<PlayCircleOutlined />}
onClick={reloadPage}
className="ml-2"
>
Play Now
</Button>
}
/>
) : null}
</div>
{!isLoaded && (
<div className="relative w-full h-full flex flex-col items-center justify-center bg-white/50">

View file

@ -310,6 +310,7 @@ interface Props {
panelHeight: number;
onClose?: () => void;
activeOutsideIndex?: number;
isSpot?: boolean;
}
export const NetworkPanelComp = observer(
@ -331,6 +332,7 @@ export const NetworkPanelComp = observer(
zoomEndTs,
onClose,
activeOutsideIndex,
isSpot,
}: Props) => {
const { showModal } = useModal();
const [sortBy, setSortBy] = useState('time');
@ -500,6 +502,7 @@ export const NetworkPanelComp = observer(
setIsDetailsModalActive(true);
showModal(
<FetchDetailsModal
isSpot={isSpot}
time={item.time + startedAt}
resource={item}
rows={filteredList}

View file

@ -12,9 +12,10 @@ interface Props {
time?: number;
rows?: any;
fetchPresented?: boolean;
isSpot?: boolean;
}
function FetchDetailsModal(props: Props) {
const { rows = [], fetchPresented = false } = props;
const { rows = [], fetchPresented = false, isSpot } = props;
const [resource, setResource] = useState(props.resource);
const [first, setFirst] = useState(false);
const [last, setLast] = useState(false);
@ -57,7 +58,7 @@ function FetchDetailsModal(props: Props) {
<h5 className="mb-4 text-2xl ">Network Request</h5>
<FetchBasicDetails resource={resource} timestamp={props.time ? DateTime.fromMillis(props.time).setZone(timezone.value).toFormat(`hh:mm:ss a`) : undefined} />
{isXHR && <FetchTabs resource={resource} />}
{isXHR && <FetchTabs isSpot={isSpot} resource={resource} />}
{rows && rows.length > 0 && (
<div className="flex justify-between absolute bottom-0 left-0 right-0 p-3 border-t bg-white">

View file

@ -24,23 +24,16 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
<div className="flex items-start py-1">
<div className="font-medium w-36">Name</div>
<Tag
className="text-base max-w-96 rounded-lg text-clip bg-indigo-50 whitespace-nowrap overflow-hidden text-clip cursor-pointer word-break"
className="text-base max-w-80 rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis cursor-pointer word-break"
bordered={false}>
<CopyText content={resource.url}>{resource.url}</CopyText>
</Tag>
</div>
<div className="flex items-center py-1">
<div className="font-medium w-36">Type</div>
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip" bordered={false}>
{resource.type}
</Tag>
</div>
{resource.method && (
<div className="flex items-center py-1">
<div className="font-medium w-36">Request Method</div>
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip"
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis"
bordered={false}>
{resource.method}
</Tag>
@ -53,7 +46,7 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
<Tag
bordered={false}
className={cn(
'text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip flex items-center',
'text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis flex items-center',
{ 'error color-red': !resource.success }
)}
>
@ -64,7 +57,7 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
<div className="flex items-center py-1">
<div className="font-medium w-36">Type</div>
<Tag className="text-base capitalize rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip"
<Tag className="text-base capitalize rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis"
bordered={false}>
{resource.type}
</Tag>
@ -73,7 +66,7 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
{!!resource.decodedBodySize && (
<div className="flex items-center py-1">
<div className="font-medium w-36">Size</div>
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip"
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis"
bordered={false}>
{formatBytes(resource.decodedBodySize)}
</Tag>
@ -84,7 +77,7 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
{!!_duration && (
<div className="flex items-center py-1">
<div className="font-medium w-36">Duration</div>
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip"
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis"
bordered={false}>
{_duration} ms
</Tag>
@ -94,7 +87,7 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
{timestamp && (
<div className="flex items-center py-1">
<div className="font-medium w-36">Time</div>
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-clip"
<Tag className="text-base rounded-lg bg-indigo-50 whitespace-nowrap overflow-hidden text-ellipsis"
bordered={false}>
{timestamp}
</Tag>

View file

@ -71,8 +71,9 @@ function parseRequestResponse(
interface Props {
resource: { request: string, response: string };
isSpot?: boolean;
}
function FetchTabs({ resource }: Props) {
function FetchTabs({ resource, isSpot }: Props) {
const [activeTab, setActiveTab] = useState(HEADERS);
const onTabClick = (tab: string) => setActiveTab(tab);
const [jsonRequest, setJsonRequest] = useState<Object | null>(null);
@ -84,7 +85,6 @@ function FetchTabs({ resource }: Props) {
useEffect(() => {
const { request, response } = resource;
console.log(resource, request, response)
parseRequestResponse(
request,
setRequestHeaders,
@ -119,7 +119,7 @@ function FetchTabs({ resource }: Props) {
</div>
}
size="small"
show={!jsonRequest && !stringRequest}
show={!isSpot && !jsonRequest && !stringRequest}
// animatedIcon="no-results"
>
<div>
@ -151,7 +151,7 @@ function FetchTabs({ resource }: Props) {
</div>
}
size="small"
show={!jsonResponse && !stringResponse}
show={!isSpot && !jsonResponse && !stringResponse}
// animatedIcon="no-results"
>
<div>

View file

@ -303,7 +303,7 @@ export default class Widget {
} else if (this.metricType === INSIGHTS) {
_data['issues'] = data
.filter((i: any) => i.change > 0 || i.change < 0)
x .map(
.map(
(i: any) =>
new InsightIssue(i.category, i.name, i.ratio, i.oldValue, i.value, i.change, i.isNew)
);

View file

@ -13,15 +13,14 @@ function Settings({ goBack }: { goBack: () => void }) {
onMount(() => {
chrome.storage.local.get("settings", (data: any) => {
if (data.settings) {
const ingest = data.settings.ingestPoint || "https://app.openreplay.com";
const devToolsEnabled =
data.settings.consoleLogs && data.settings.networkLogs;
setOpenInNewTab(data.settings.openInNewTab ?? false);
setIncludeDevTools(devToolsEnabled);
setShowIngest(data.settings.showIngest ?? true);
setIngest(data.settings.ingestPoint || "https://app.openreplay.com");
setTempIngest(
data.settings.ingestPoint || "https://app.openreplay.com",
);
setIngest(ingest);
setTempIngest(ingest);
setShowIngest(ingest !== "https://app.openreplay.com");
setEditIngest(!data.settings.ingestPoint);
}
});