mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[DevTools] Tweak the presentation of the Promise value (#34097)
Show the value as "fulfilled: Type" or "rejected: Type" immediately instead of having to expand it twice. We could show all the properties of the object immediately like we do in the Performance Track but it's not always particularly interesting data in the value that isn't already in the header. I also moved it to the end after the stack traces since I think the stack is more interesting but I'm also visually trying to connect the stack trace with the "name" since typically the "name" will come from part of the stack trace. Before: <img width="517" height="433" alt="Screenshot 2025-08-03 at 11 39 49 PM" src="https://github.com/user-attachments/assets/ad28d8a2-c149-4957-a393-20ff3932a819" /> After: <img width="520" height="476" alt="Screenshot 2025-08-03 at 11 58 35 PM" src="https://github.com/user-attachments/assets/53a755b0-bb68-4305-9d16-d6fac7ca4910" />
This commit is contained in:
parent
557745eb0b
commit
be11cb5c4b
|
|
@ -490,7 +490,7 @@ export function logComponentAwait(
|
||||||
if (typeof value === 'object' && value !== null) {
|
if (typeof value === 'object' && value !== null) {
|
||||||
addObjectToProperties(value, properties, 0, '');
|
addObjectToProperties(value, properties, 0, '');
|
||||||
} else if (value !== undefined) {
|
} else if (value !== undefined) {
|
||||||
addValueToProperties('Resolved', value, properties, 0, '');
|
addValueToProperties('awaited value', value, properties, 0, '');
|
||||||
}
|
}
|
||||||
const tooltipText = getIOLongName(
|
const tooltipText = getIOLongName(
|
||||||
asyncInfo.awaited,
|
asyncInfo.awaited,
|
||||||
|
|
@ -547,7 +547,7 @@ export function logIOInfoErrored(
|
||||||
String(error.message)
|
String(error.message)
|
||||||
: // eslint-disable-next-line react-internal/safe-string-coercion
|
: // eslint-disable-next-line react-internal/safe-string-coercion
|
||||||
String(error);
|
String(error);
|
||||||
const properties = [['Rejected', message]];
|
const properties = [['rejected with', message]];
|
||||||
const tooltipText =
|
const tooltipText =
|
||||||
getIOLongName(ioInfo, description, ioInfo.env, rootEnv) + ' Rejected';
|
getIOLongName(ioInfo, description, ioInfo.env, rootEnv) + ' Rejected';
|
||||||
debugTask.run(
|
debugTask.run(
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.CollapsableContent {
|
.CollapsableContent {
|
||||||
padding: 0.25rem 0;
|
margin-top: -0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.PreviewContainer {
|
.PreviewContainer {
|
||||||
padding: 0 0.25rem 0.25rem 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TimeBarContainer {
|
.TimeBarContainer {
|
||||||
|
|
|
||||||
|
|
@ -107,11 +107,10 @@ function SuspendedByRow({
|
||||||
}
|
}
|
||||||
|
|
||||||
const value: any = asyncInfo.awaited.value;
|
const value: any = asyncInfo.awaited.value;
|
||||||
const isErrored =
|
const metaName =
|
||||||
value !== null &&
|
value !== null && typeof value === 'object' ? value[meta.name] : null;
|
||||||
typeof value === 'object' &&
|
const isFulfilled = metaName === 'fulfilled Thenable';
|
||||||
value[meta.name] === 'rejected Thenable';
|
const isRejected = metaName === 'rejected Thenable';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.CollapsableRow}>
|
<div className={styles.CollapsableRow}>
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -136,7 +135,7 @@ function SuspendedByRow({
|
||||||
<div className={styles.TimeBarContainer}>
|
<div className={styles.TimeBarContainer}>
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
!isErrored ? styles.TimeBarSpan : styles.TimeBarSpanErrored
|
!isRejected ? styles.TimeBarSpan : styles.TimeBarSpanErrored
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
left: left.toFixed(2) + '%',
|
left: left.toFixed(2) + '%',
|
||||||
|
|
@ -147,24 +146,6 @@ function SuspendedByRow({
|
||||||
</Button>
|
</Button>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className={styles.CollapsableContent}>
|
<div className={styles.CollapsableContent}>
|
||||||
<div className={styles.PreviewContainer}>
|
|
||||||
<KeyValue
|
|
||||||
alphaSort={true}
|
|
||||||
bridge={bridge}
|
|
||||||
canDeletePaths={false}
|
|
||||||
canEditValues={false}
|
|
||||||
canRenamePaths={false}
|
|
||||||
depth={1}
|
|
||||||
element={element}
|
|
||||||
hidden={false}
|
|
||||||
inspectedElement={inspectedElement}
|
|
||||||
name={'Promise'}
|
|
||||||
path={[index, 'awaited', 'value']}
|
|
||||||
pathRoot="suspendedBy"
|
|
||||||
store={store}
|
|
||||||
value={asyncInfo.awaited.value}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{stack !== null && stack.length > 0 && (
|
{stack !== null && stack.length > 0 && (
|
||||||
<StackTraceView stack={stack} />
|
<StackTraceView stack={stack} />
|
||||||
)}
|
)}
|
||||||
|
|
@ -179,6 +160,38 @@ function SuspendedByRow({
|
||||||
type={owner.type}
|
type={owner.type}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
<div className={styles.PreviewContainer}>
|
||||||
|
<KeyValue
|
||||||
|
alphaSort={true}
|
||||||
|
bridge={bridge}
|
||||||
|
canDeletePaths={false}
|
||||||
|
canEditValues={false}
|
||||||
|
canRenamePaths={false}
|
||||||
|
depth={1}
|
||||||
|
element={element}
|
||||||
|
hidden={false}
|
||||||
|
inspectedElement={inspectedElement}
|
||||||
|
name={
|
||||||
|
isFulfilled
|
||||||
|
? 'awaited value'
|
||||||
|
: isRejected
|
||||||
|
? 'rejected with'
|
||||||
|
: 'pending value'
|
||||||
|
}
|
||||||
|
path={
|
||||||
|
isFulfilled
|
||||||
|
? [index, 'awaited', 'value', 'value']
|
||||||
|
: isRejected
|
||||||
|
? [index, 'awaited', 'value', 'reason']
|
||||||
|
: [index, 'awaited', 'value']
|
||||||
|
}
|
||||||
|
pathRoot="suspendedBy"
|
||||||
|
store={store}
|
||||||
|
value={
|
||||||
|
isFulfilled ? value.value : isRejected ? value.reason : value
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
11
packages/react-devtools-shared/src/hydration.js
vendored
11
packages/react-devtools-shared/src/hydration.js
vendored
|
|
@ -21,6 +21,8 @@ import type {
|
||||||
InspectedElementPath,
|
InspectedElementPath,
|
||||||
} from 'react-devtools-shared/src/frontend/types';
|
} from 'react-devtools-shared/src/frontend/types';
|
||||||
|
|
||||||
|
import noop from 'shared/noop';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
inspectable: (Symbol('inspectable'): symbol),
|
inspectable: (Symbol('inspectable'): symbol),
|
||||||
inspected: (Symbol('inspected'): symbol),
|
inspected: (Symbol('inspected'): symbol),
|
||||||
|
|
@ -317,6 +319,15 @@ export function dehydrate(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
data.status === 'resolved_model' ||
|
||||||
|
data.status === 'resolve_module'
|
||||||
|
) {
|
||||||
|
// This looks it's a lazy initialization pattern such in Flight.
|
||||||
|
// Since we're about to inspect it. Let's eagerly initialize it.
|
||||||
|
data.then(noop);
|
||||||
|
}
|
||||||
|
|
||||||
switch (data.status) {
|
switch (data.status) {
|
||||||
case 'fulfilled': {
|
case 'fulfilled': {
|
||||||
const unserializableValue: Unserializable = {
|
const unserializableValue: Unserializable = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user