diff --git a/README.md b/README.md index d1af9c91e6..279cb9c191 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,39 @@ [![OpenCollective](https://opencollective.com/redux-devtools-extension/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/redux-devtools-extension/sponsors/badge.svg)](#sponsors) -# Redux DevTools +# Redux DevTools (Custom Version) + +This fork of [Redux DevTools](https://github.com/reduxjs/redux-devtools) includes enhanced styling for better trace readability and JetBrains product support for code opening from traces when using the JavaScript debugger and the built-in server at the default port 63342. + +## Features + +- Improved trace styles for increased readability. +- Added support for opening code directly from traces in JetBrains IDEs (like WebStorm, IntelliJ IDEA, etc.). + +### JetBrains Integration + +To use the JetBrains integration: + +1. Set `External editor:` to `jetbrains_server`. +2. Set `Absolute path to the project directory to open:` to `/`. + +### Fix issue with background color of the trace panel. + +## Fix issue with the background black color of the trace tab. + +1. --- + +![FH6fkptVOW](https://github.com/IliyaBrook/redux-devtools/assets/60712617/0fef78a6-e98a-4298-b347-f7f3b5d2e52b) + + +## Add copy to clipboard functionality to TreeView, in State and Action tabs. + +2. --- + +![copy_paste](https://github.com/IliyaBrook/redux-devtools/assets/60712617/67fc8242-ec83-467a-a8ba-1e20fdb91f52) + + +## Original Redux DevTools Developer Tools to power-up [Redux](https://redux.js.org/) development workflow or any other architecture which handles the state change (see [integrations](https://github.com/reduxjs/redux-devtools/blob/main/extension/docs/Integrations.md)). diff --git a/extension/chrome/manifest.json b/extension/chrome/manifest.json index 7369d6c8a5..a1b33abaeb 100644 --- a/extension/chrome/manifest.json +++ b/extension/chrome/manifest.json @@ -61,7 +61,9 @@ "storage", "file:///*", "http://*/*", - "https://*/*" + "https://*/*", + "clipboardWrite", + "clipboardRead" ], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;", "update_url": "https://clients2.google.com/service/update2/crx", diff --git a/extension/edge/manifest.json b/extension/edge/manifest.json index 00fb14e6c3..097ea2ca00 100644 --- a/extension/edge/manifest.json +++ b/extension/edge/manifest.json @@ -61,7 +61,9 @@ "storage", "file:///*", "http://*/*", - "https://*/*" + "https://*/*", + "clipboardWrite", + "clipboardRead" ], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" } diff --git a/extension/firefox/manifest.json b/extension/firefox/manifest.json index c19b76e8b2..7bf83536df 100644 --- a/extension/firefox/manifest.json +++ b/extension/firefox/manifest.json @@ -57,7 +57,9 @@ "storage", "file:///*", "http://*/*", - "https://*/*" + "https://*/*", + "clipboardWrite", + "clipboardRead" ], "content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self' data:;" } diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts b/packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts index eabda508be..a64b3f91ed 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts +++ b/packages/redux-devtools-inspector-monitor-trace-tab/src/openFile.ts @@ -84,6 +84,10 @@ function openInEditor(editor: string, path: string, stackFrame: StackFrame) { case 'idea': url = `${editor}://open?file=${projectPath}${filePath}&line=${line}&column=${column}`; break; + // add support for jetbrains server + case 'jetbrains_server': + url = `http://localhost:63342/api/file/?file=${filePath}&line=${line}`; + break; default: // sublime, emacs, macvim, textmate + custom like https://github.com/eclemens/atom-url-handler url = `${editor}://open/?url=file://${projectPath}${filePath}&line=${line}&column=${column}`; diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx index 2c3a1b2ca4..bb8c9d7de5 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx +++ b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/CodeBlock.tsx @@ -10,17 +10,19 @@ import React, { CSSProperties } from 'react'; const preStyle: CSSProperties = { position: 'relative', display: 'block', - backgroundColor: '#000', + backgroundColor: '#f7f7f7', padding: '0.5em', marginTop: '0.5em', marginBottom: '0.5em', overflowX: 'auto', whiteSpace: 'pre-wrap', borderRadius: '0.25rem', + border: '1px solid #ddd', }; const codeStyle = { fontFamily: 'Consolas, Menlo, monospace', + color: '#333', }; interface CodeBlockPropsType { diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx index 07e81b6460..c450981249 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx +++ b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/components/Collapsible.tsx @@ -19,6 +19,7 @@ const _collapsibleStyle: CSSProperties = { fontSize: '1em', padding: '0px 5px', lineHeight: '1.5', + borderBottom: '1px solid #ddd', }; const collapsibleCollapsedStyle: CSSProperties = { diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx index f5efb14412..e9d34c97f9 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx +++ b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrame.tsx @@ -16,16 +16,18 @@ import type { ErrorLocation } from '../utils/parseCompileError'; const linkStyle: CSSProperties = { fontSize: '0.9em', marginBottom: '0.9em', + color: '#0645AD', }; const anchorStyle: CSSProperties = { textDecoration: 'none', - color: theme.base05, + color: '#0645AD', cursor: 'pointer', }; const codeAnchorStyle: CSSProperties = { cursor: 'pointer', + color: '#333', }; const toggleStyle: CSSProperties = { diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx index e599a33701..0b1566d578 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx +++ b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackFrameCodeBlock.tsx @@ -13,7 +13,6 @@ import { ScriptLine } from '../utils/stack-frame'; import generateAnsiHTML from '../utils/generateAnsiHTML'; import { codeFrameColumns } from '@babel/code-frame'; -import { nicinabox as theme } from 'redux-devtools-themes'; interface StackFrameCodeBlockPropsType { lines: ScriptLine[]; @@ -86,7 +85,7 @@ function StackFrameCodeBlock(props: StackFrameCodeBlockPropsType) { } // $FlowFixMe applyStyles(node as HTMLElement, { - backgroundColor: main ? theme.base02 : theme.base01, + backgroundColor: '#e0e0e0', }); // eslint-disable-next-line break oLoop; diff --git a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx index 6c329b57a1..a7845ee910 100644 --- a/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx +++ b/packages/redux-devtools-inspector-monitor-trace-tab/src/react-error-overlay/containers/StackTrace.tsx @@ -19,6 +19,8 @@ const traceStyle = { flex: '0 1 auto', minHeight: '0px', overflow: 'auto', + color: '#000', + backgroundColor: '#f7f7f7', }; interface Props { diff --git a/packages/redux-devtools-inspector-monitor/package.json b/packages/redux-devtools-inspector-monitor/package.json index 2808dcffee..1db31dcfa8 100644 --- a/packages/redux-devtools-inspector-monitor/package.json +++ b/packages/redux-devtools-inspector-monitor/package.json @@ -47,6 +47,7 @@ "immutable": "^4.3.5", "javascript-stringify": "^2.1.0", "jsondiffpatch": "^0.6.0", + "lodash.clonedeep": "^4.5.0", "lodash.debounce": "^4.0.8", "react-base16-styling": "^0.9.1", "react-json-tree": "^0.18.0", @@ -66,6 +67,7 @@ "@types/dateformat": "^5.0.2", "@types/hex-rgba": "^1.0.3", "@types/history": "^4.7.11", + "@types/lodash.clonedeep": "^4.5.9", "@types/lodash.debounce": "^4.0.9", "@types/react": "^18.2.58", "@typescript-eslint/eslint-plugin": "^6.21.0", diff --git a/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx b/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx index 3427fb2d3b..a3837b0284 100644 --- a/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx +++ b/packages/redux-devtools-inspector-monitor/src/ActionPreview.tsx @@ -10,6 +10,8 @@ import ActionPreviewHeader from './ActionPreviewHeader'; import DiffTab from './tabs/DiffTab'; import StateTab from './tabs/StateTab'; import ActionTab from './tabs/ActionTab'; +import { getValueByPath } from './utils/getValueByPath'; +import { copyToClipboard } from './utils/copyToClipboard'; export interface TabComponentProps> { labelRenderer: LabelRenderer; @@ -184,7 +186,7 @@ class ActionPreview> extends Component< labelRenderer: LabelRenderer = ([key, ...rest], nodeType, expanded) => { const { onInspectPath, inspectedPath } = this.props; - + const reversedPath = [key, ...rest].reverse(); return ( {key} @@ -202,14 +204,41 @@ class ActionPreview> extends Component< onClick={() => onInspectPath([ ...inspectedPath.slice(0, inspectedPath.length - 1), - ...[key, ...rest].reverse(), + ...reversedPath, ]) } > - {'(pin)'} - - {!expanded && ': '} + {'(pin)'} + ({ + fontSize: '0.7em', + paddingLeft: '5px', + cursor: 'pointer', + '&:hover': { + textDecoration: 'underline', + }, + color: theme.PIN_COLOR, + })} + onClick={event => { + event.stopPropagation(); + let objectForCopying; + if (this.props.tabName === 'Action') { + objectForCopying = getValueByPath(this.props.action, reversedPath); + } else if (this.props.tabName === 'State') { + objectForCopying = getValueByPath(this.props.nextState, reversedPath); + } + if (objectForCopying !== undefined) { + copyToClipboard(objectForCopying); + } else { + console.error('Unable to find the object to copy'); + } + }} + > + {'(copy)'} + + {!expanded && ': '} + ); }; } diff --git a/packages/redux-devtools-inspector-monitor/src/utils/copyToClipboard.ts b/packages/redux-devtools-inspector-monitor/src/utils/copyToClipboard.ts new file mode 100644 index 0000000000..39f4021c46 --- /dev/null +++ b/packages/redux-devtools-inspector-monitor/src/utils/copyToClipboard.ts @@ -0,0 +1,11 @@ +import cloneDeep from 'lodash.clonedeep'; + +export function copyToClipboard(object: any){ + try { + const deepCopiedObject = cloneDeep(object); + const jsonString = JSON.stringify(deepCopiedObject, null, 2); + void navigator.clipboard.writeText(jsonString); + } catch (err) { + console.error('Error during copy: ', err); + } +} diff --git a/packages/redux-devtools-inspector-monitor/src/utils/getValueByPath.ts b/packages/redux-devtools-inspector-monitor/src/utils/getValueByPath.ts new file mode 100644 index 0000000000..f98ce1c288 --- /dev/null +++ b/packages/redux-devtools-inspector-monitor/src/utils/getValueByPath.ts @@ -0,0 +1,12 @@ +export function getValueByPath(obj: any, path: (string | number)[]){ + let current: any = obj; + for (let i = 0; i < path.length; i++) { + const key = path[i]; + const adjustedKey = typeof key === 'string' && !isNaN(Number(key)) ? parseInt(key, 10) : key; + if (current[adjustedKey] === undefined) { + return undefined; + } + current = current[adjustedKey]; + } + return current; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e1b769dd14..93903bf9a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1614,6 +1614,9 @@ importers: jsondiffpatch: specifier: ^0.6.0 version: 0.6.0 + lodash.clonedeep: + specifier: ^4.5.0 + version: 4.5.0 lodash.debounce: specifier: ^4.0.8 version: 4.0.8 @@ -1669,6 +1672,9 @@ importers: '@types/history': specifier: ^4.7.11 version: 4.7.11 + '@types/lodash.clonedeep': + specifier: ^4.5.9 + version: 4.5.9 '@types/lodash.debounce': specifier: ^4.0.9 version: 4.0.9 @@ -10273,6 +10279,12 @@ packages: '@types/lodash': 4.14.202 dev: true + /@types/lodash.clonedeep@4.5.9: + resolution: {integrity: sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q==} + dependencies: + '@types/lodash': 4.14.202 + dev: true + /@types/lodash.curry@4.1.9: resolution: {integrity: sha512-QV967vSflHEza0d0IMTK7fwbl+baPBXZjcESeAHrA5eSE+EHetaggZjPpkzX1NJh4qa8DLOLScwUR+f7FN85Zg==} dependencies: @@ -16841,6 +16853,10 @@ packages: /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + /lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + dev: false + /lodash.curry@4.1.1: resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==} dev: false