diff --git a/packages/react-devtools-shared/package.json b/packages/react-devtools-shared/package.json index 09551aadddbaa..7e83263687aa0 100644 --- a/packages/react-devtools-shared/package.json +++ b/packages/react-devtools-shared/package.json @@ -8,6 +8,7 @@ }, "dependencies": { "@babel/runtime": "^7.11.2", + "@octokit/rest": "^18.5.2", "@reach/menu-button": "^0.1.17", "@reach/tooltip": "^0.2.2", "clipboard-js": "^0.3.6", diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js index da7784c759374..b9d3ba23e56e3 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js @@ -14,3 +14,4 @@ ************************************************************************/ export const enableProfilerChangedHookIndices = false; +export const isInternalFacebookBuild = false; diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js index 08fb7178c75ba..104cf263091a7 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js @@ -14,6 +14,7 @@ ************************************************************************/ export const enableProfilerChangedHookIndices = true; +export const isInternalFacebookBuild = true; /************************************************************************ * Do not edit the code below. diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js index 6ad795840d58a..4d1b1472bba69 100644 --- a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js @@ -14,6 +14,7 @@ ************************************************************************/ export const enableProfilerChangedHookIndices = false; +export const isInternalFacebookBuild = false; /************************************************************************ * Do not edit the code below. diff --git a/packages/react-devtools-shared/src/constants.js b/packages/react-devtools-shared/src/constants.js index bae23abc01223..7babb90cff377 100644 --- a/packages/react-devtools-shared/src/constants.js +++ b/packages/react-devtools-shared/src/constants.js @@ -49,6 +49,9 @@ export const CHANGE_LOG_URL = export const UNSUPPORTED_VERSION_URL = 'https://reactjs.org/blog/2019/08/15/new-react-devtools.html#how-do-i-get-the-old-version-back'; +export const REACT_DEVTOOLS_WORKPLACE_URL = + 'https://fburl.com/react-devtools-workplace-group'; + // HACK // // Extracting during build time avoids a temporarily invalid state for the inline target. diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary.css b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary.css deleted file mode 100644 index d16964aabaf2d..0000000000000 --- a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary.css +++ /dev/null @@ -1,54 +0,0 @@ -.ErrorBoundary { - height: 100%; - width: 100%; - background-color: var(--color-background); - padding: 0.5rem; - overflow: auto; -} - -.Header { - font-size: var(--font-size-sans-large); - font-weight: bold; - color: var(--color-error-text); -} - -.Stack { - margin-top: 0.5rem; - white-space: pre-wrap; - font-family: var(--font-family-monospace); - font-size: var(--font-size-monospace-normal); - -webkit-font-smoothing: initial; - background-color: var(--color-error-background); - border: 1px solid var(--color-error-border); - color: var(--color-error-text); - border-radius: 0.25rem; - padding: 0.5rem; -} - -.IconAndLinkRow { - display: flex; - align-items: center; - margin-top: 0.5rem; - color: var(--color-text); -} - -.RetryIcon { - margin-right: 0.25rem; - color: var(--color-button-active); -} - -.RetryButton { - margin-right: 0.25rem; - color: var(--color-text); -} -.RetryButton:hover { - color: var(--color-button-hover); -} - -.ReportIcon { - margin-right: 0.25rem; -} - -.ReportLink { - color: var(--color-link); -} \ No newline at end of file diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary.js deleted file mode 100644 index 7b777115d3b5e..0000000000000 --- a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary.js +++ /dev/null @@ -1,154 +0,0 @@ -/** - * 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 {Component} from 'react'; -import Button from './Button'; -import ButtonIcon from './ButtonIcon'; -import Icon from './Icon'; -import styles from './ErrorBoundary.css'; -import Store from 'react-devtools-shared/src/devtools/store'; - -type Props = {| - children: React$Node, - onRetry?: (store: Store) => void, - store: Store, -|}; - -type State = {| - callStack: string | null, - componentStack: string | null, - errorMessage: string | null, - hasError: boolean, -|}; - -const InitialState: State = { - callStack: null, - componentStack: null, - errorMessage: null, - hasError: false, -}; - -export default class ErrorBoundary extends Component { - state: State = InitialState; - - static getDerivedStateFromError(error: any) { - const errorMessage = - typeof error === 'object' && - error !== null && - error.hasOwnProperty('message') - ? error.message - : error; - - return { - errorMessage, - hasError: true, - }; - } - - componentDidCatch(error: any, {componentStack}: any) { - const callStack = - typeof error === 'object' && - error !== null && - error.hasOwnProperty('stack') - ? error.stack - .split('\n') - .slice(1) - .join('\n') - : null; - - this.setState({ - callStack, - componentStack, - }); - } - - render() { - const {children} = this.props; - const {callStack, componentStack, errorMessage, hasError} = this.state; - - let bugURL = process.env.GITHUB_URL; - if (bugURL) { - const title = `Error: "${errorMessage || ''}"`; - const label = 'Component: Developer Tools'; - - let body = 'Describe what you were doing when the bug occurred:'; - body += '\n1. '; - body += '\n2. '; - body += '\n3. '; - body += '\n\n---------------------------------------------'; - body += '\nPlease do not remove the text below this line'; - body += '\n---------------------------------------------'; - body += `\n\nDevTools version: ${process.env.DEVTOOLS_VERSION || ''}`; - if (callStack) { - body += `\n\nCall stack: ${callStack.trim()}`; - } - if (componentStack) { - body += `\n\nComponent stack: ${componentStack.trim()}`; - } - - bugURL += `/issues/new?labels=${encodeURI(label)}&title=${encodeURI( - title, - )}&body=${encodeURI(body)}`; - } - - if (hasError) { - return ( -
-
- Uncaught Error: {errorMessage || ''} -
-
- - {bugURL && ( - <> - - - Report this issue - - - )} -
- {!!callStack && ( -
- The error was thrown {callStack.trim()} -
- )} - {!!componentStack && ( -
- The error occurred {componentStack.trim()} -
- )} -
- ); - } - - return children; - } - - handleRetry = () => { - const {onRetry, store} = this.props; - if (typeof onRetry === 'function') { - onRetry(store); - } - - this.setState(InitialState); - }; -} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js new file mode 100644 index 0000000000000..3d633cf5dca29 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorBoundary.js @@ -0,0 +1,91 @@ +/** + * 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 {Component, Suspense} from 'react'; +import ErrorView from './ErrorView'; +import SearchingGitHubIssues from './SearchingGitHubIssues'; +import SuspendingErrorView from './SuspendingErrorView'; + +type Props = {| + children: React$Node, +|}; + +type State = {| + callStack: string | null, + componentStack: string | null, + errorMessage: string | null, + hasError: boolean, +|}; + +const InitialState: State = { + callStack: null, + componentStack: null, + errorMessage: null, + hasError: false, +}; + +export default class ErrorBoundary extends Component { + state: State = InitialState; + + static getDerivedStateFromError(error: any) { + const errorMessage = + typeof error === 'object' && + error !== null && + error.hasOwnProperty('message') + ? error.message + : '' + error; + + return { + errorMessage, + hasError: true, + }; + } + + componentDidCatch(error: any, {componentStack}: any) { + const callStack = + typeof error === 'object' && + error !== null && + error.hasOwnProperty('stack') + ? error.stack + .split('\n') + .slice(1) + .join('\n') + : null; + + this.setState({ + callStack, + componentStack, + }); + } + + render() { + const {children} = this.props; + const {callStack, componentStack, errorMessage, hasError} = this.state; + + if (hasError) { + return ( + + }> + + + + ); + } + + return children; + } +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorView.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorView.js new file mode 100644 index 0000000000000..6ec792408fe9c --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ErrorView.js @@ -0,0 +1,46 @@ +/** + * 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 styles from './shared.css'; + +type Props = {| + callStack: string | null, + children: React$Node, + componentStack: string | null, + errorMessage: string | null, +|}; + +export default function ErrorView({ + callStack, + children, + componentStack, + errorMessage, +}: Props) { + return ( +
+ {children} +
+
+ Uncaught Error: {errorMessage || ''} +
+ {!!callStack && ( +
+ The error was thrown {callStack.trim()} +
+ )} + {!!componentStack && ( +
+ The error occurred {componentStack.trim()} +
+ )} +
+
+ ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ReportNewIssue.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ReportNewIssue.js new file mode 100644 index 0000000000000..d54115ef6d7c5 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ReportNewIssue.js @@ -0,0 +1,68 @@ +/** + * 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 Icon from '../Icon'; +import styles from './shared.css'; + +type Props = {| + callStack: string | null, + componentStack: string | null, + errorMessage: string | null, +|}; + +export default function ReportNewIssue({ + callStack, + componentStack, + errorMessage, +}: Props) { + let bugURL = process.env.GITHUB_URL; + if (!bugURL) { + return null; + } + + const title = `Error: "${errorMessage || ''}"`; + const label = 'Component: Developer Tools'; + + let body = 'Describe what you were doing when the bug occurred:'; + body += '\n1. '; + body += '\n2. '; + body += '\n3. '; + body += '\n\n---------------------------------------------'; + body += '\nPlease do not remove the text below this line'; + body += '\n---------------------------------------------'; + body += `\n\nDevTools version: ${process.env.DEVTOOLS_VERSION || ''}`; + if (callStack) { + body += `\n\nCall stack: ${callStack.trim()}`; + } + if (componentStack) { + body += `\n\nComponent stack: ${componentStack.trim()}`; + } + + bugURL += `/issues/new?labels=${encodeURI(label)}&title=${encodeURI( + title, + )}&body=${encodeURI(body)}`; + + return ( +
+ + + Report this issue + +
+ (Please include steps on how to reproduce it and the components used.) +
+
+ ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/SearchingGitHubIssues.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/SearchingGitHubIssues.js new file mode 100644 index 0000000000000..b7f993b2395d3 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/SearchingGitHubIssues.js @@ -0,0 +1,21 @@ +/** + * 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 LoadingAnimation from 'react-devtools-shared/src/devtools/views/Components/LoadingAnimation'; +import styles from './shared.css'; + +export default function SearchingGitHubIssues() { + return ( +
+ + Searching GitHub for reports of this error... +
+ ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/SuspendingErrorView.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/SuspendingErrorView.js new file mode 100644 index 0000000000000..f44e166b3a57f --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/SuspendingErrorView.js @@ -0,0 +1,49 @@ +/** + * 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 {findGitHubIssue} from './cache'; +import UpdateExistingIssue from './UpdateExistingIssue'; +import ReportNewIssue from './ReportNewIssue'; +import WorkplaceGroup from './WorkplaceGroup'; + +type Props = {| + callStack: string | null, + componentStack: string | null, + errorMessage: string | null, +|}; + +export default function SuspendingErrorView({ + callStack, + componentStack, + errorMessage, +}: Props) { + const maybeItem = + errorMessage !== null ? findGitHubIssue(errorMessage) : null; + + let GitHubUI; + if (maybeItem != null) { + GitHubUI = ; + } else { + GitHubUI = ( + + ); + } + + return ( + <> + {GitHubUI} + + + ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/UpdateExistingIssue.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/UpdateExistingIssue.js new file mode 100644 index 0000000000000..ad1139d935a2b --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/UpdateExistingIssue.js @@ -0,0 +1,38 @@ +/** + * 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 type {GitHubIssue} from './githubAPI'; + +import * as React from 'react'; +import Icon from '../Icon'; +import styles from './shared.css'; + +export default function UpdateExistingIssue({ + gitHubIssue, +}: {| + gitHubIssue: GitHubIssue, +|}) { + const {title, url} = gitHubIssue; + return ( +
+ +
+ Update existing issue: +
+ + {title} + +
+ ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/WorkplaceGroup.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/WorkplaceGroup.js new file mode 100644 index 0000000000000..f885f9611f5bb --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/WorkplaceGroup.js @@ -0,0 +1,35 @@ +/** + * 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 {isInternalFacebookBuild} from 'react-devtools-feature-flags'; +import {REACT_DEVTOOLS_WORKPLACE_URL} from 'react-devtools-shared/src/constants'; +import Icon from '../Icon'; +import styles from './shared.css'; + +export default function WorkplaceGroup() { + if (!isInternalFacebookBuild) { + return null; + } + + return ( +
+ + + Report this on Workplace + +
(Facebook employees only.)
+
+ ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/cache.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/cache.js new file mode 100644 index 0000000000000..cc9dca2179865 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/cache.js @@ -0,0 +1,134 @@ +/** + * 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 type {Wakeable} from 'shared/ReactTypes'; +import type {GitHubIssue} from './githubAPI'; + +import {unstable_getCacheForType} from 'react'; +import {searchGitHubIssues} from './githubAPI'; + +const API_TIMEOUT = 3000; + +const Pending = 0; +const Resolved = 1; +const Rejected = 2; + +type PendingRecord = {| + status: 0, + value: Wakeable, +|}; + +type ResolvedRecord = {| + status: 1, + value: T, +|}; + +type RejectedRecord = {| + status: 2, + value: null, +|}; + +type Record = PendingRecord | ResolvedRecord | RejectedRecord; + +function readRecord(record: Record): ResolvedRecord | RejectedRecord { + if (record.status === Resolved) { + // This is just a type refinement. + return record; + } else if (record.status === Rejected) { + // This is just a type refinement. + return record; + } else { + throw record.value; + } +} + +type GitHubIssueMap = Map>; + +function createMap(): GitHubIssueMap { + return new Map(); +} + +function getRecordMap(): Map> { + return unstable_getCacheForType(createMap); +} + +export function findGitHubIssue(errorMessage: string): GitHubIssue | null { + errorMessage = normalizeErrorMessage(errorMessage); + + const map = getRecordMap(); + let record = map.get(errorMessage); + + if (!record) { + const callbacks = new Set(); + const wakeable: Wakeable = { + then(callback) { + callbacks.add(callback); + }, + }; + const wake = () => { + // This assumes they won't throw. + callbacks.forEach(callback => callback()); + callbacks.clear(); + }; + const newRecord: Record = (record = { + status: Pending, + value: wakeable, + }); + + let didTimeout = false; + + searchGitHubIssues(errorMessage) + .then(maybeItem => { + if (didTimeout) { + return; + } + + if (maybeItem) { + const resolvedRecord = ((newRecord: any): ResolvedRecord); + resolvedRecord.status = Resolved; + resolvedRecord.value = maybeItem; + } else { + const notFoundRecord = ((newRecord: any): RejectedRecord); + notFoundRecord.status = Rejected; + notFoundRecord.value = null; + } + + wake(); + }) + .catch(error => { + const thrownRecord = ((newRecord: any): RejectedRecord); + thrownRecord.status = Rejected; + thrownRecord.value = null; + + wake(); + }); + + // Only wait a little while for GitHub results before showing a fallback. + setTimeout(() => { + didTimeout = true; + + const timedoutRecord = ((newRecord: any): RejectedRecord); + timedoutRecord.status = Rejected; + timedoutRecord.value = null; + + wake(); + }, API_TIMEOUT); + + map.set(errorMessage, record); + } + + const response = readRecord(record).value; + return response; +} + +function normalizeErrorMessage(errorMessage: string): string { + // Remove Fiber IDs from error message (as those will be unique). + errorMessage = errorMessage.replace(/"[0-9]+"/, ''); + return errorMessage; +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/githubAPI.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/githubAPI.js new file mode 100644 index 0000000000000..7f990e4be4824 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/githubAPI.js @@ -0,0 +1,50 @@ +/** + * 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 {Octokit} from '@octokit/rest'; + +export type GitHubIssue = {| + title: string, + url: string, +|}; + +export async function searchGitHubIssues( + message: string, +): Promise { + // Remove Fiber IDs from error message (as those will be unique). + message = message.replace(/"[0-9]+"/, ''); + + const filters = [ + // Unfortunately "repo" and "org" filters don't work + // Hopefully the label filter will be sufficient. + 'in:title', + 'is:issue', + 'is:open', + 'is:public', + 'label:"Component: Developer Tools"', + ]; + + const octokit = new Octokit(); + const {data} = await octokit.search.issuesAndPullRequests({ + q: message + ' ' + filters.join(' '), + }); + + const maybeItem = data.items.find(item => + item.html_url.startsWith('https://github.com/facebook/react/'), + ); + + if (maybeItem) { + return { + title: maybeItem.title, + url: maybeItem.html_url, + }; + } else { + return null; + } +} diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/index.js b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/index.js new file mode 100644 index 0000000000000..0d1d0cc390582 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/index.js @@ -0,0 +1,12 @@ +/** + * 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 ErrorBoundary from './ErrorBoundary'; + +export default ErrorBoundary; diff --git a/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/shared.css b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/shared.css new file mode 100644 index 0000000000000..267cfad7b7e88 --- /dev/null +++ b/packages/react-devtools-shared/src/devtools/views/ErrorBoundary/shared.css @@ -0,0 +1,83 @@ +.GitHubLinkRow { + flex: 0 0 auto; + display: flex; + align-items: center; + text-overflow: ellipsis; + white-space: nowrap; + overflow: auto; + padding: 0.25rem 0.5rem; + background: var(--color-console-warning-background); + color: var(--color-text); + border-bottom: 1px solid var(--color-console-warning-border); + border-top: 1px solid var(--color-console-warning-border); +} + +.WorkplaceGroupRow { + flex: 0 0 auto; + display: flex; + align-items: center; + text-overflow: ellipsis; + white-space: nowrap; + overflow: auto; + padding: 0.25rem 0.5rem; + background: var(--color-background-hover); + border-bottom: 1px solid var(--color-border); +} + +.ErrorBoundary { + height: 100%; + width: 100%; + background-color: var(--color-background); + display: flex; + flex-direction: column; +} + +.ErrorInfo { + padding: 0.5rem; + overflow: auto; +} + +.Header { + font-size: var(--font-size-sans-large); + font-weight: bold; + color: var(--color-error-text); +} + +.Stack { + margin-top: 0.5rem; + white-space: pre-wrap; + font-family: var(--font-family-monospace); + font-size: var(--font-size-monospace-normal); + -webkit-font-smoothing: initial; + background-color: var(--color-error-background); + border: 1px solid var(--color-error-border); + color: var(--color-error-text); + border-radius: 0.25rem; + padding: 0.5rem; +} + +.LoadingIcon { + margin-right: 0.25rem; +} + +.ReportIcon { + margin-right: 0.25rem; +} + +.ReportLink { + color: var(--color-link); +} + +.FacebookOnly { + margin-left: 0.25rem; +} + +.ReproSteps { + margin-left: 0.25rem; + color: var(--color-console-warning-text); +} + +.UpdateExistingIssuePrompt { + margin-right: 0.25rem; + color: var(--color-console-warning-text); +} \ No newline at end of file diff --git a/packages/react-devtools-shared/src/devtools/views/Icon.js b/packages/react-devtools-shared/src/devtools/views/Icon.js index ce02611127f31..e879acdbfa614 100644 --- a/packages/react-devtools-shared/src/devtools/views/Icon.js +++ b/packages/react-devtools-shared/src/devtools/views/Icon.js @@ -17,6 +17,7 @@ export type IconType = | 'components' | 'copy' | 'error' + | 'facebook' | 'flame-chart' | 'interactions' | 'profiler' @@ -52,6 +53,9 @@ export default function Icon({className = '', type}: Props) { case 'error': pathData = PATH_ERROR; break; + case 'facebook': + pathData = PATH_FACEBOOK; + break; case 'flame-chart': pathData = PATH_FLAME_CHART; break; @@ -117,6 +121,10 @@ const PATH_COPY = ` const PATH_ERROR = `M16.971 0h-9.942l-7.029 7.029v9.941l7.029 7.03h9.941l7.03-7.029v-9.942l-7.029-7.029zm-1.402 16.945l-3.554-3.521-3.518 3.568-1.418-1.418 3.507-3.566-3.586-3.472 1.418-1.417 3.581 3.458 3.539-3.583 1.431 1.431-3.535 3.568 3.566 3.522-1.431 1.43z`; +const PATH_FACEBOOK = ` + M22,12c0-5.52-4.48-10-10-10S2,6.48,2,12c0,4.84,3.44,8.87,8,9.8V15H8v-3h2V9.5C10,7.57,11.57,6,13.5,6H16v3h-2 c-0.55,0-1,0.45-1,1v2h3v3h-3v6.95C18.05,21.45,22,17.19,22,12z +`; + const PATH_FLAME_CHART = ` M10.0650893,21.5040462 C7.14020814,20.6850349 5,18.0558698 5,14.9390244 C5,14.017627 5,9.81707317 7.83333333,7.37804878 C7.83333333,7.37804878 7.58333333,11.199187 10, diff --git a/yarn.lock b/yarn.lock index 9daccaf78bb36..861beb4325550 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1814,6 +1814,26 @@ read-package-json-fast "^1.1.1" readdir-scoped-modules "^1.1.0" +"@octokit/auth-token@^2.4.4": + version "2.4.5" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3" + integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA== + dependencies: + "@octokit/types" "^6.0.3" + +"@octokit/core@^3.2.3": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.4.0.tgz#b48aa27d755b339fe7550548b340dcc2b513b742" + integrity sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg== + dependencies: + "@octokit/auth-token" "^2.4.4" + "@octokit/graphql" "^4.5.8" + "@octokit/request" "^5.4.12" + "@octokit/request-error" "^2.0.5" + "@octokit/types" "^6.0.3" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + "@octokit/endpoint@^5.1.0": version "5.3.2" resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.3.2.tgz#2deda2d869cac9ba7f370287d55667be2a808d4b" @@ -1824,6 +1844,49 @@ universal-user-agent "^3.0.0" url-template "^2.0.8" +"@octokit/endpoint@^6.0.1": + version "6.0.11" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1" + integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ== + dependencies: + "@octokit/types" "^6.0.3" + is-plain-object "^5.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^4.5.8": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.6.1.tgz#f975486a46c94b7dbe58a0ca751935edc7e32cc9" + integrity sha512-2lYlvf4YTDgZCTXTW4+OX+9WTLFtEUc6hGm4qM1nlZjzxj+arizM4aHWzBVBCxY9glh7GIs0WEuiSgbVzv8cmA== + dependencies: + "@octokit/request" "^5.3.0" + "@octokit/types" "^6.0.3" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-6.0.0.tgz#7da8d7d5a72d3282c1a3ff9f951c8133a707480d" + integrity sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ== + +"@octokit/plugin-paginate-rest@^2.6.2": + version "2.13.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz#f0f1792230805108762d87906fb02d573b9e070a" + integrity sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg== + dependencies: + "@octokit/types" "^6.11.0" + +"@octokit/plugin-request-log@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d" + integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ== + +"@octokit/plugin-rest-endpoint-methods@5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.0.0.tgz#cf2cdeb24ea829c31688216a5b165010b61f9a98" + integrity sha512-Jc7CLNUueIshXT+HWt6T+M0sySPjF32mSFQAK7UfAg8qGeRI6OM1GSBxDLwbXjkqy2NVdnqCedJcP1nC785JYg== + dependencies: + "@octokit/types" "^6.13.0" + deprecation "^2.3.1" + "@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": version "1.0.4" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.0.4.tgz#15e1dc22123ba4a9a4391914d80ec1e5303a23be" @@ -1832,6 +1895,15 @@ deprecation "^2.0.0" once "^1.4.0" +"@octokit/request-error@^2.0.0", "@octokit/request-error@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143" + integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg== + dependencies: + "@octokit/types" "^6.0.3" + deprecation "^2.0.0" + once "^1.4.0" + "@octokit/request@^5.0.0": version "5.0.2" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.0.2.tgz#59a920451f24811c016ddc507adcc41aafb2dca5" @@ -1845,6 +1917,18 @@ once "^1.4.0" universal-user-agent "^3.0.0" +"@octokit/request@^5.3.0", "@octokit/request@^5.4.12": + version "5.4.15" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.15.tgz#829da413dc7dd3aa5e2cdbb1c7d0ebe1f146a128" + integrity sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag== + dependencies: + "@octokit/endpoint" "^6.0.1" + "@octokit/request-error" "^2.0.0" + "@octokit/types" "^6.7.1" + is-plain-object "^5.0.0" + node-fetch "^2.6.1" + universal-user-agent "^6.0.0" + "@octokit/rest@^16.14.1": version "16.28.7" resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.28.7.tgz#a2c2db5b318da84144beba82d19c1a9dbdb1a1fa" @@ -1864,6 +1948,23 @@ universal-user-agent "^3.0.0" url-template "^2.0.8" +"@octokit/rest@^18.5.2": + version "18.5.2" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.5.2.tgz#0369e554b7076e3749005147be94c661c7a5a74b" + integrity sha512-Kz03XYfKS0yYdi61BkL9/aJ0pP2A/WK5vF/syhu9/kY30J8He3P68hv9GRpn8bULFx2K0A9MEErn4v3QEdbZcw== + dependencies: + "@octokit/core" "^3.2.3" + "@octokit/plugin-paginate-rest" "^2.6.2" + "@octokit/plugin-request-log" "^1.0.2" + "@octokit/plugin-rest-endpoint-methods" "5.0.0" + +"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.13.0", "@octokit/types@^6.7.1": + version "6.13.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.13.0.tgz#779e5b7566c8dde68f2f6273861dd2f0409480d0" + integrity sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA== + dependencies: + "@octokit/openapi-types" "^6.0.0" + "@pmmmwh/react-refresh-webpack-plugin@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.1.tgz#a4db0ed8e58c2f8566161c9a8cdf1d095c9a891b" @@ -3478,6 +3579,11 @@ before-after-hook@^2.0.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== +before-after-hook@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.1.tgz#73540563558687586b52ed217dad6a802ab1549c" + integrity sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw== + big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -5140,7 +5246,7 @@ depd@^1.1.2, depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -deprecation@^2.0.0: +deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== @@ -8128,6 +8234,11 @@ is-plain-object@^3.0.0: dependencies: isobject "^4.0.0" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -10042,6 +10153,11 @@ node-fetch@^2.3.0, node-fetch@^2.6.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -13801,6 +13917,11 @@ universal-user-agent@^3.0.0: dependencies: os-name "^3.0.0" +universal-user-agent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" + integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"