188 lines
4.6 KiB
JavaScript
188 lines
4.6 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import * as React from 'react';
|
|
import {
|
|
useContext,
|
|
unstable_useCacheRefresh as useCacheRefresh,
|
|
useTransition,
|
|
} from 'react';
|
|
import Button from '../Button';
|
|
import ButtonIcon from '../ButtonIcon';
|
|
import Store from '../../store';
|
|
import sharedStyles from './InspectedElementSharedStyles.css';
|
|
import styles from './InspectedElementErrorsAndWarningsTree.css';
|
|
import {SettingsContext} from '../Settings/SettingsContext';
|
|
import {
|
|
clearErrorsForElement as clearErrorsForElementAPI,
|
|
clearWarningsForElement as clearWarningsForElementAPI,
|
|
} from 'react-devtools-shared/src/backendAPI';
|
|
|
|
import type {InspectedElement} from './types';
|
|
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
|
|
|
|
type Props = {|
|
|
bridge: FrontendBridge,
|
|
inspectedElement: InspectedElement,
|
|
store: Store,
|
|
|};
|
|
|
|
export default function InspectedElementErrorsAndWarningsTree({
|
|
bridge,
|
|
inspectedElement,
|
|
store,
|
|
}: Props) {
|
|
const refresh = useCacheRefresh();
|
|
|
|
const [
|
|
isErrorsTransitionPending,
|
|
startClearErrorsTransition,
|
|
] = useTransition();
|
|
const clearErrorsForInspectedElement = () => {
|
|
const {id} = inspectedElement;
|
|
const rendererID = store.getRendererIDForElement(id);
|
|
if (rendererID !== null) {
|
|
startClearErrorsTransition(() => {
|
|
clearErrorsForElementAPI({
|
|
bridge,
|
|
id,
|
|
rendererID,
|
|
});
|
|
refresh();
|
|
});
|
|
}
|
|
};
|
|
|
|
const [
|
|
isWarningsTransitionPending,
|
|
startClearWarningsTransition,
|
|
] = useTransition();
|
|
const clearWarningsForInspectedElement = () => {
|
|
const {id} = inspectedElement;
|
|
const rendererID = store.getRendererIDForElement(id);
|
|
if (rendererID !== null) {
|
|
startClearWarningsTransition(() => {
|
|
clearWarningsForElementAPI({
|
|
bridge,
|
|
id,
|
|
rendererID,
|
|
});
|
|
refresh();
|
|
});
|
|
}
|
|
};
|
|
|
|
const {showInlineWarningsAndErrors} = useContext(SettingsContext);
|
|
if (!showInlineWarningsAndErrors) {
|
|
return null;
|
|
}
|
|
|
|
const {errors, warnings} = inspectedElement;
|
|
|
|
return (
|
|
<React.Fragment>
|
|
{errors.length > 0 && (
|
|
<Tree
|
|
badgeClassName={styles.ErrorBadge}
|
|
bridge={bridge}
|
|
className={styles.ErrorTree}
|
|
clearMessages={clearErrorsForInspectedElement}
|
|
entries={errors}
|
|
isTransitionPending={isErrorsTransitionPending}
|
|
label="errors"
|
|
messageClassName={styles.Error}
|
|
/>
|
|
)}
|
|
{warnings.length > 0 && (
|
|
<Tree
|
|
badgeClassName={styles.WarningBadge}
|
|
bridge={bridge}
|
|
className={styles.WarningTree}
|
|
clearMessages={clearWarningsForInspectedElement}
|
|
entries={warnings}
|
|
isTransitionPending={isWarningsTransitionPending}
|
|
label="warnings"
|
|
messageClassName={styles.Warning}
|
|
/>
|
|
)}
|
|
</React.Fragment>
|
|
);
|
|
}
|
|
|
|
type TreeProps = {|
|
|
badgeClassName: string,
|
|
actions: React$Node,
|
|
className: string,
|
|
clearMessages: () => {},
|
|
entries: Array<[string, number]>,
|
|
isTransitionPending: boolean,
|
|
label: string,
|
|
messageClassName: string,
|
|
|};
|
|
|
|
function Tree({
|
|
badgeClassName,
|
|
actions,
|
|
className,
|
|
clearMessages,
|
|
entries,
|
|
isTransitionPending,
|
|
label,
|
|
messageClassName,
|
|
}: TreeProps) {
|
|
if (entries.length === 0) {
|
|
return null;
|
|
}
|
|
return (
|
|
<div className={`${sharedStyles.InspectedElementTree} ${className}`}>
|
|
<div className={`${sharedStyles.HeaderRow} ${styles.HeaderRow}`}>
|
|
<div className={sharedStyles.Header}>{label}</div>
|
|
<Button
|
|
disabled={isTransitionPending}
|
|
onClick={clearMessages}
|
|
title={`Clear all ${label} for this component`}>
|
|
<ButtonIcon type="clear" />
|
|
</Button>
|
|
</div>
|
|
{entries.map(([message, count], index) => (
|
|
<ErrorOrWarningView
|
|
key={`${label}-${index}`}
|
|
badgeClassName={badgeClassName}
|
|
className={messageClassName}
|
|
count={count}
|
|
message={message}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
type ErrorOrWarningViewProps = {|
|
|
badgeClassName: string,
|
|
className: string,
|
|
count: number,
|
|
message: string,
|
|
|};
|
|
|
|
function ErrorOrWarningView({
|
|
className,
|
|
badgeClassName,
|
|
count,
|
|
message,
|
|
}: ErrorOrWarningViewProps) {
|
|
return (
|
|
<div className={className}>
|
|
{count > 1 && <div className={badgeClassName}>{count}</div>}
|
|
<div className={styles.Message} title={message}>
|
|
{message}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|