From eb5a9c91c2627e4f4340dfdf7059c315b9440681 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 16 Oct 2025 23:39:07 -0400 Subject: [PATCH 1/3] Use the environment of the timeline step as a label or "Suspense" if no environment --- .../views/SuspenseTab/SuspenseScrubber.js | 25 +++++++++++-------- .../views/SuspenseTab/SuspenseTimeline.js | 1 + 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js index f1998aff4b16c..9b63c4dcb4bd6 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js @@ -7,6 +7,8 @@ * @flow */ +import type {SuspenseTimelineStep} from 'react-devtools-shared/src/frontend/types'; + import typeof {SyntheticEvent} from 'react-dom-bindings/src/events/SyntheticEvent'; import * as React from 'react'; @@ -19,6 +21,7 @@ import Tooltip from '../Components/reach-ui/tooltip'; export default function SuspenseScrubber({ min, max, + timeline, value, highlight, onBlur, @@ -29,6 +32,7 @@ export default function SuspenseScrubber({ }: { min: number, max: number, + timeline: $ReadOnlyArray, value: number, highlight: number, onBlur?: () => void, @@ -54,17 +58,18 @@ export default function SuspenseScrubber({ } const steps = []; for (let index = min; index <= max; index++) { + const environment = timeline[index].environment; + const label = + index === min + ? // The first step in the timeline is always a Transition (Initial Paint). + 'Initial Paint' + + (environment === null ? '' : ' (' + environment + ')') + : // TODO: Consider adding the name of this specific boundary if this step has only one. + environment === null + ? 'Suspense' + : environment; steps.push( - +
Date: Thu, 16 Oct 2025 23:47:45 -0400 Subject: [PATCH 2/3] Use different color configurations for different environments --- .../src/devtools/constants.js | 8 +++--- .../Components/InspectedElementSuspendedBy.js | 14 ++++++++-- .../SuspenseTab/SuspenseEnvironmentColors.css | 14 ++++++++++ .../SuspenseTab/SuspenseEnvironmentColors.js | 20 +++++++++++++ .../views/SuspenseTab/SuspenseRects.js | 28 +++++++++++++++---- .../views/SuspenseTab/SuspenseScrubber.js | 5 +++- 6 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseEnvironmentColors.css create mode 100644 packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseEnvironmentColors.js diff --git a/packages/react-devtools-shared/src/devtools/constants.js b/packages/react-devtools-shared/src/devtools/constants.js index 5c90501d70f5c..d093a798bcd30 100644 --- a/packages/react-devtools-shared/src/devtools/constants.js +++ b/packages/react-devtools-shared/src/devtools/constants.js @@ -154,8 +154,8 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any, ...} = { '--color-warning-text-color': '#ffffff', '--color-warning-text-color-inverted': '#fd4d69', - '--color-suspense': '#0088fa', - '--color-transition': '#6a51b2', + '--color-suspense-default': '#0088fa', + '--color-transition-default': '#6a51b2', '--color-suspense-server': '#62bc6a', '--color-transition-server': '#3f7844', '--color-suspense-other': '#f3ce49', @@ -315,8 +315,8 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any, ...} = { '--color-warning-text-color': '#ffffff', '--color-warning-text-color-inverted': '#ee1638', - '--color-suspense': '#61dafb', - '--color-transition': '#6a51b2', + '--color-suspense-default': '#61dafb', + '--color-transition-default': '#6a51b2', '--color-suspense-server': '#62bc6a', '--color-transition-server': '#3f7844', '--color-suspense-other': '#f3ce49', diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js index 9078d3c3beabc..0f94f83596a89 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js @@ -22,6 +22,8 @@ import OwnerView from './OwnerView'; import {meta} from '../../../hydration'; import useInferredName from '../useInferredName'; +import {getClassNameForEnvironment} from '../SuspenseTab/SuspenseEnvironmentColors.js'; + import type { InspectedElement, SerializedAsyncInfo, @@ -181,7 +183,12 @@ function SuspendedByRow({ )}
-
+
{pluralizedName}
{isOpen ? null : ( -
+
-1 && timeline[hoveredTimelineIndex].id === suspenseID; + let environment: null | string = null; + for (let i = 0; i < timeline.length; i++) { + const timelineStep = timeline[i]; + if (timelineStep.id === suspenseID) { + environment = timelineStep.environment; + break; + } + } + const boundingBox = getBoundingBox(suspense.rects); return ( From 81496e0f5c2dd4cce8b0b839c862d2c5291516d6 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Fri, 17 Oct 2025 00:17:24 -0400 Subject: [PATCH 3/3] Group by environment name so that we can assign the color --- .../views/Components/InspectedElementSuspendedBy.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js index 0f94f83596a89..78c137deaf37c 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js @@ -348,6 +348,7 @@ type GroupProps = { inspectedElement: InspectedElement, store: Store, name: string, + environment: null | string, suspendedBy: Array<{ index: number, value: SerializedAsyncInfo, @@ -362,6 +363,7 @@ function SuspendedByGroup({ inspectedElement, store, name, + environment, suspendedBy, minTime, maxTime, @@ -416,7 +418,9 @@ function SuspendedByGroup({ {isOpen ? null : (