diff --git a/src/components/RecentActivity/LiveView/ChangeStatus/index.tsx b/src/components/RecentActivity/LiveView/ChangeStatus/index.tsx
index a45bd46dc..30d0ae38d 100644
--- a/src/components/RecentActivity/LiveView/ChangeStatus/index.tsx
+++ b/src/components/RecentActivity/LiveView/ChangeStatus/index.tsx
@@ -5,9 +5,6 @@ import { LiveDataDurationPercentile } from "../types";
import * as s from "./styles";
import { ChangeStatusProps } from "./types";
-const DURATION_RATIO_MIN_LIMIT = 0.1;
-const DURATION_DIFF_MIN_LIMIT = 10 * 1000; // in nanoseconds
-
const getStatusString = (percentile: LiveDataDurationPercentile) => {
if (!percentile.previousDuration) {
return "";
@@ -74,39 +71,12 @@ const renderArrowIcon = (
export const ChangeStatus = (props: ChangeStatusProps) => {
const theme = useTheme();
- if (props.percentiles.length === 0) {
- return null;
- }
-
- const percentile = props.percentiles.find(
- (x) => x.previousDuration && typeof x.changeVerified === "boolean"
- );
-
- if (!percentile) {
- return null;
- }
-
- let changeMeaningfulEnough = false;
-
- if (percentile.previousDuration) {
- const diff = Math.abs(
- percentile.currentDuration.raw - percentile.previousDuration.raw
- );
-
- changeMeaningfulEnough =
- diff / percentile.previousDuration.raw > DURATION_RATIO_MIN_LIMIT &&
- diff > DURATION_DIFF_MIN_LIMIT;
- }
-
- if (!changeMeaningfulEnough) {
- return null;
- }
return (
- {renderArrowIcon(percentile, theme)}
- {getStatusString(percentile)}
- {!percentile.changeVerified && (
+ {renderArrowIcon(props.percentile, theme)}
+ {getStatusString(props.percentile)}
+ {!props.percentile.changeVerified && (
Evaluating
)}
diff --git a/src/components/RecentActivity/LiveView/ChangeStatus/types.ts b/src/components/RecentActivity/LiveView/ChangeStatus/types.ts
index e7cd021fc..33774d49b 100644
--- a/src/components/RecentActivity/LiveView/ChangeStatus/types.ts
+++ b/src/components/RecentActivity/LiveView/ChangeStatus/types.ts
@@ -1,5 +1,5 @@
import { LiveDataDurationPercentile } from "../types";
export interface ChangeStatusProps {
- percentiles: LiveDataDurationPercentile[];
+ percentile: LiveDataDurationPercentile;
}
diff --git a/src/components/RecentActivity/LiveView/index.tsx b/src/components/RecentActivity/LiveView/index.tsx
index 72534b96c..18356c09e 100644
--- a/src/components/RecentActivity/LiveView/index.tsx
+++ b/src/components/RecentActivity/LiveView/index.tsx
@@ -1,5 +1,5 @@
import { format } from "date-fns";
-import { UIEvent, useEffect, useRef, useState } from "react";
+import { UIEvent, useEffect, useMemo, useRef, useState } from "react";
import useDimensions from "react-cool-dimensions";
import useScrollbarSize from "react-scrollbar-size";
@@ -40,6 +40,8 @@ import {
} from "./types";
const ZOOM_FACTOR = 1.2;
+const DURATION_RATIO_MIN_LIMIT = 0.1;
+const DURATION_DIFF_MIN_LIMIT = 10 * 1000; // in nanoseconds
const PERCENTILES = [
{ label: "Median", percentile: 0.5 },
@@ -328,8 +330,40 @@ export const LiveView = (props: LiveViewProps) => {
? scrollbar.width
: 0;
+ const changedPercentile = useMemo(() => {
+ if (props.data.durationData.percentiles.length === 0) {
+ return null;
+ }
+
+ const percentile = props.data.durationData.percentiles.find(
+ (x) => x.previousDuration && typeof x.changeVerified === "boolean"
+ );
+
+ if (!percentile) {
+ return null;
+ }
+
+ let changeMeaningfulEnough = false;
+
+ if (percentile.previousDuration) {
+ const diff = Math.abs(
+ percentile.currentDuration.raw - percentile.previousDuration.raw
+ );
+
+ changeMeaningfulEnough =
+ diff / percentile.previousDuration.raw > DURATION_RATIO_MIN_LIMIT &&
+ diff > DURATION_DIFF_MIN_LIMIT;
+ }
+
+ if (!changeMeaningfulEnough) {
+ return null;
+ }
+
+ return percentile;
+ }, [props.data.durationData.percentiles]);
+
return (
-
+
@@ -355,10 +389,14 @@ export const LiveView = (props: LiveViewProps) => {
-
-
-
-
+ {changedPercentile && (
+
+
+
+ )}
+
+ [
+ HEADER_HEIGHT,
+ ZOOM_BUTTONS_CONTAINER_HEIGHT,
+ isChangeStatusBarPresent ? CHANGE_STATUS_CONTAINER_HEIGHT : 0,
+ FOOTER_HEIGHT
+ ]
+ .filter((x) => x > 0)
+ .reduce((acc, cur) => acc + cur + CONTAINER_GAP, 0) + CONTAINER_GAP;
+
+export const Container = styled.div<{ isChangeStatusBarPresent: boolean }>`
display: flex;
flex-direction: column;
height: 100%;
- gap: 12px;
+ gap: ${CONTAINER_GAP}px;
+ min-height: ${({ isChangeStatusBarPresent }) =>
+ getContainerMinHeight(isChangeStatusBarPresent)}px;
border: 1px solid
${({ theme }) => {
@@ -37,6 +56,9 @@ export const Header = styled.div`
font-weight: 500;
font-size: 10px;
line-height: 12px;
+ height: ${HEADER_HEIGHT}px;
+ box-sizing: border-box;
+ flex: none;
border-bottom: ${({ theme }) => {
switch (theme.mode) {
@@ -114,9 +136,15 @@ export const CloseButton = styled.button`
cursor: pointer;
`;
-export const ChartsContainer = styled.div`
+export const ChartsContainer = styled.div<{
+ isChangeStatusBarPresent: boolean;
+}>`
display: flex;
- height: calc(100% - 174px);
+ height: calc(
+ 100% -
+ ${({ isChangeStatusBarPresent }) =>
+ getContainerMinHeight(isChangeStatusBarPresent)}px
+ );
padding-right: 12px;
`;
@@ -125,6 +153,8 @@ export const ZoomButtonsContainer = styled.div`
justify-content: flex-end;
gap: 4px;
padding: 0 12px;
+ height: ${ZOOM_BUTTONS_CONTAINER_HEIGHT}px;
+ flex: none;
`;
export const ZoomButton = styled.button`
@@ -168,7 +198,8 @@ export const ZoomButton = styled.button`
export const ChangeStatusContainer = styled.div`
padding: 0 12px;
- height: 32px;
+ height: ${CHANGE_STATUS_CONTAINER_HEIGHT}px;
+ flex: none;
`;
export const AxisChartContainer = styled.div`
@@ -189,6 +220,9 @@ export const Footer = styled.div`
flex-direction: column;
gap: 4px;
padding: 4px 12px;
+ height: ${FOOTER_HEIGHT}px;
+ box-sizing: border-box;
+ flex: none;
`;
export const LegendContainer = styled.div`