diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 3b1538dd..8f77d9fb 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,7 +15,7 @@ jobs: with: fetch-depth: 0 - uses: nrwl/nx-set-shas@v4 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - uses: actions/setup-node@v4 with: node-version: 'lts/*' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f3ac63f..270b1e31 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v4 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.gitignore b/.gitignore index 2df6ebc3..34daf06a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ coverage .idea .eslintcache !packages/redux-devtools-slider-monitor/examples/todomvc/dist/index.html -.nx/cache +.nx diff --git a/eslint.js.config.base.mjs b/eslint.js.config.base.mjs new file mode 100644 index 00000000..31f147f9 --- /dev/null +++ b/eslint.js.config.base.mjs @@ -0,0 +1,4 @@ +import eslint from '@eslint/js'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default [eslint.configs.recommended, eslintConfigPrettier]; diff --git a/eslint.ts.config.base.mjs b/eslint.ts.config.base.mjs new file mode 100644 index 00000000..2af98f40 --- /dev/null +++ b/eslint.ts.config.base.mjs @@ -0,0 +1,55 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default (tsconfigRootDir, files = ['**/*.ts'], project = true) => [ + { + files, + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files, + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files, + ...config, + })), + { + files, + languageOptions: { + parserOptions: { + project, + tsconfigRootDir, + }, + }, + }, + { + files, + ...eslintConfigPrettier, + }, + { + files, + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + }, + }, +]; diff --git a/eslint.ts.jest.config.base.mjs b/eslint.ts.jest.config.base.mjs new file mode 100644 index 00000000..fd916a03 --- /dev/null +++ b/eslint.ts.jest.config.base.mjs @@ -0,0 +1,64 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import jest from 'eslint-plugin-jest'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default (tsconfigRootDir) => [ + { + files: ['test/**/*.ts'], + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files: ['test/**/*.ts'], + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files: ['test/**/*.ts'], + ...config, + })), + { + files: ['test/**/*.ts'], + languageOptions: { + parserOptions: { + project: ['./tsconfig.test.json'], + tsconfigRootDir, + }, + }, + }, + { + files: ['test/**/*.ts'], + ...jest.configs['flat/recommended'], + }, + { + files: ['test/**/*.ts'], + ...jest.configs['jest/style'], + }, + { + files: ['test/**/*.ts'], + ...eslintConfigPrettier, + }, + { + files: ['test/**/*.ts'], + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + }, + }, +]; diff --git a/eslint.ts.react.config.base.mjs b/eslint.ts.react.config.base.mjs new file mode 100644 index 00000000..110f1e8a --- /dev/null +++ b/eslint.ts.react.config.base.mjs @@ -0,0 +1,89 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import react from 'eslint-plugin-react'; +import { fixupPluginRules } from '@eslint/compat'; +import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default ( + tsconfigRootDir, + files = ['**/*.ts', '**/*.tsx'], + project = true, +) => [ + { + files, + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files, + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files, + ...config, + })), + { + files, + languageOptions: { + parserOptions: { + project, + tsconfigRootDir, + }, + }, + }, + { + files, + ...react.configs.flat.recommended, + }, + { + files, + settings: { + react: { + version: 'detect', + }, + }, + }, + { + files, + plugins: { + 'react-hooks': fixupPluginRules(eslintPluginReactHooks), + }, + }, + { + files, + ...eslintConfigPrettier, + }, + { + files, + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-misused-promises': [ + 'error', + { + checksVoidReturn: { + attributes: false, + }, + }, + ], + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + 'react/prop-types': 'off', + }, + }, +]; diff --git a/eslint.ts.react.jest.config.base.mjs b/eslint.ts.react.jest.config.base.mjs new file mode 100644 index 00000000..f0db2ab2 --- /dev/null +++ b/eslint.ts.react.jest.config.base.mjs @@ -0,0 +1,85 @@ +import eslint from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import react from 'eslint-plugin-react'; +import { fixupPluginRules } from '@eslint/compat'; +import eslintPluginReactHooks from 'eslint-plugin-react-hooks'; +import jest from 'eslint-plugin-jest'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default (tsconfigRootDir) => [ + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...eslint.configs.recommended, + }, + ...tseslint.configs.recommendedTypeChecked.map((config) => ({ + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...config, + })), + ...tseslint.configs.stylisticTypeChecked.map((config) => ({ + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...config, + })), + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + languageOptions: { + parserOptions: { + project: ['./tsconfig.test.json'], + tsconfigRootDir, + }, + }, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...react.configs.flat.recommended, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + settings: { + react: { + version: 'detect', + }, + }, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + plugins: { + 'react-hooks': fixupPluginRules(eslintPluginReactHooks), + }, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...jest.configs['flat/recommended'], + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...jest.configs['jest/style'], + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + ...eslintConfigPrettier, + }, + { + files: ['test/**/*.ts', 'test/**/*.tsx'], + rules: { + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/non-nullable-type-assertion-style': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/prefer-string-starts-ends-with': 'off', + '@typescript-eslint/no-duplicate-type-constituents': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/prefer-function-type': 'off', + }, + }, +]; diff --git a/eslintrc.js.base.json b/eslintrc.js.base.json deleted file mode 100644 index a059126a..00000000 --- a/eslintrc.js.base.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parser": "@babel/eslint-parser" -} diff --git a/eslintrc.ts.base.json b/eslintrc.ts.base.json deleted file mode 100644 index cdd3764d..00000000 --- a/eslintrc.ts.base.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "prettier" - ], - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/eslintrc.ts.jest.base.json b/eslintrc.ts.jest.base.json deleted file mode 100644 index 8a8cde2d..00000000 --- a/eslintrc.ts.jest.base.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "plugins": ["jest"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:jest/recommended", - "plugin:jest/style", - "prettier" - ], - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/eslintrc.ts.react.base.json b/eslintrc.ts.react.base.json deleted file mode 100644 index f17dc31c..00000000 --- a/eslintrc.ts.react.base.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - } - }, - "plugins": ["@typescript-eslint", "react"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - "prettier" - ], - "settings": { - "react": { - "version": "detect" - } - }, - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-misused-promises": [ - "error", - { - "checksVoidReturn": { - "attributes": false - } - } - ], - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/eslintrc.ts.react.jest.base.json b/eslintrc.ts.react.jest.base.json deleted file mode 100644 index 80fbfee6..00000000 --- a/eslintrc.ts.react.jest.base.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "plugins": ["jest"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - "plugin:jest/recommended", - "plugin:jest/style", - "prettier" - ], - "rules": { - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/prefer-optional-chain": "off", - "@typescript-eslint/no-base-to-string": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/non-nullable-type-assertion-style": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/prefer-string-starts-ends-with": "off", - "@typescript-eslint/no-duplicate-type-constituents": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/prefer-function-type": "off" - } -} diff --git a/extension/CHANGELOG.md b/extension/CHANGELOG.md index 88b0b2dc..e3f26bb5 100644 --- a/extension/CHANGELOG.md +++ b/extension/CHANGELOG.md @@ -1,5 +1,42 @@ # remotedev-redux-devtools-extension +## 3.2.4 + +### Patch Changes + +- f1d6158: Fix mocking Chrome API for Electron + +## 3.2.3 + +### Patch Changes + +- fd9f950: Fix monitoring on opening panel +- e49708d: Fix manifest.json for Edge + +## 3.2.1 + +### Patch Changes + +- abd03a7: Fix: only send data to extension if DevTools are open + +## 3.2.0 + +### Minor Changes + +- 83b2c19: Upgrade to Manifest V3 + +## 3.1.11 + +### Patch Changes + +- 73688e1: Fix releasing Firefox extension + +## 3.1.10 + +### Patch Changes + +- 2163bc3: Split large messages sent from background page to devpanel + ## 3.1.9 ### Patch Changes diff --git a/extension/build.mjs b/extension/build.mjs index 86971a68..9c378cf4 100644 --- a/extension/build.mjs +++ b/extension/build.mjs @@ -5,7 +5,7 @@ import pug from 'pug'; const args = process.argv.slice(2); const prod = !args.includes('--dev'); -const commonEsbuildOptions = { +await esbuild.build({ bundle: true, logLevel: 'info', outdir: 'dist', @@ -15,40 +15,24 @@ const commonEsbuildOptions = { 'process.env.NODE_ENV': prod ? '"production"' : '"development"', 'process.env.BABEL_ENV': prod ? '"production"' : '"development"', }, -}; - -await esbuild.build({ - ...commonEsbuildOptions, entryPoints: [ { out: 'background.bundle', in: 'src/background/index.ts' }, { out: 'options.bundle', in: 'src/options/index.tsx' }, - { out: 'window.bundle', in: 'src/window/index.tsx' }, { out: 'remote.bundle', in: 'src/remote/index.tsx' }, { out: 'devpanel.bundle', in: 'src/devpanel/index.tsx' }, { out: 'devtools.bundle', in: 'src/devtools/index.ts' }, { out: 'content.bundle', in: 'src/contentScript/index.ts' }, { out: 'page.bundle', in: 'src/pageScript/index.ts' }, - ...(prod ? [] : [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }]), ], loader: { '.woff2': 'file', }, }); -if (prod) { - await esbuild.build({ - ...commonEsbuildOptions, - entryPoints: [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }], - loader: { - '.js': 'text', - }, - }); -} - console.log(); console.log('Creating HTML files...'); -const htmlFiles = ['devpanel', 'devtools', 'options', 'remote', 'window']; +const htmlFiles = ['devpanel', 'devtools', 'options', 'remote']; for (const htmlFile of htmlFiles) { fs.writeFileSync( `dist/${htmlFile}.html`, diff --git a/extension/chrome/manifest.json b/extension/chrome/manifest.json index 7369d6c8..50f554c1 100644 --- a/extension/chrome/manifest.json +++ b/extension/chrome/manifest.json @@ -1,28 +1,22 @@ { - "version": "3.1.6", + "version": "3.2.4", "name": "Redux DevTools", "description": "Redux DevTools for debugging application's state changes.", "homepage_url": "https://github.com/reduxjs/redux-devtools", - "manifest_version": 2, - "page_action": { + "manifest_version": 3, + "action": { "default_icon": "img/logo/gray.png", "default_title": "Redux DevTools", - "default_popup": "window.html#popup" + "default_popup": "devpanel.html#popup" }, "commands": { - "devtools-left": { - "description": "DevTools window to left" - }, - "devtools-right": { - "description": "DevTools window to right" - }, - "devtools-bottom": { - "description": "DevTools window to bottom" + "devtools-window": { + "description": "DevTools window" }, "devtools-remote": { "description": "Remote DevTools" }, - "_execute_page_action": { + "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+E" } @@ -34,36 +28,37 @@ "128": "img/logo/128x128.png" }, "options_ui": { - "page": "options.html", - "chrome_style": true + "page": "options.html" }, "background": { - "scripts": ["background.bundle.js"], - "persistent": false + "service_worker": "background.bundle.js" }, "content_scripts": [ { "matches": [""], "exclude_globs": ["https://www.google*"], - "js": ["content.bundle.js", "pagewrap.bundle.js"], + "js": ["content.bundle.js"], "run_at": "document_start", "all_frames": true + }, + { + "matches": [""], + "exclude_globs": ["https://www.google*"], + "js": ["page.bundle.js"], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" } ], "devtools_page": "devtools.html", - "web_accessible_resources": ["page.bundle.js"], "externally_connectable": { "ids": ["*"] }, - "permissions": [ - "notifications", - "contextMenus", - "storage", - "file:///*", - "http://*/*", - "https://*/*" - ], - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;", + "permissions": ["notifications", "contextMenus", "storage"], + "host_permissions": ["file:///*", "http://*/*", "https://*/*"], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" + }, "update_url": "https://clients2.google.com/service/update2/crx", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdJEPwY92xUACA9CcDBDBmbdbp8Ap3cKQ0DJTUuVQvqb4FQAv8RtKY3iUjGvdwuAcSJQIZwHXcP2aNDH3TiFik/NhRK2GRW8X3OZyTdkuDueABGP2KEX8q1WQDgjX/rPIinGYztUrvoICw/UerMPwNW62jwGoVU3YhAGf+15CgX2Y6a4tppnf/+1mPedKPidh0RsM+aJY98rX+r1SPAHPcGzMjocLkqcT75DZBXer8VQN14tOOzRCd6T6oy7qm7eWru8lJwcY66qMQvhk0osqEod2G3nA7aTWpmqPFS66VEiecP9PgZlp8gQdgZ3dFhA62exydlD55JuRhiMIR63yQIDAQAB" } diff --git a/extension/docs/Architecture.md b/extension/docs/Architecture.md new file mode 100644 index 00000000..1c8137e1 --- /dev/null +++ b/extension/docs/Architecture.md @@ -0,0 +1,37 @@ +# Architecture Notes + +This document exists to keep track of how the different parts of the Redux DevTools interact, since it's easy to forget how it all works together. This is intended for internal purposes and is just a collection of notes to myself. + +## Entry Points + +### Window + +This is the default view that is shown in the Redux DevTools popup, the Chrome DevTools tab (if direct access to the background page is available), and new popup windows that are created. It has direct access to the background page via `chrome.runtime.getBackgroundPage`. + +### DevPanel + +This is the view that is shown in the Chrome DevTools tab if direct access to the background page is not available. + +Initially this was the view that was always used for the Chrome DevTools tab, but when support to directly access the background page from the DevTools tab was added, [the Window View became the preferred view](https://github.com/zalmoxisus/redux-devtools-extension/pull/580). + +### Remote + +This does not interact with the other parts of the extension at all, it just renders the `App` component from `@redux-devtools/app`. + +It can be triggered by hitting the "Remote" button in any of the other views, which calls `chrome.windows.create` and creates a new window. + +### DevTools + +This is the script that adds the Redux panel in the Chrome DevTools using `chrome.devtools.panels.create`. + +It creates a Window View if it has direct access to the background page, otherwise it creates a DevPanel View. + +Note that this used to always show the DevPanel View, but [started using the Window View by default](https://github.com/zalmoxisus/redux-devtools-extension/pull/580) once direct access to the background page was added to Chrome DevTools tabs. + +### Content Script + +Passes messages between the injected page script and the background page. + +It listens for messages from the injected page script using `window.addEventListener('message', ...)`. It knows the message is from the injected page script if `message.source` is `'@devtools-page'`. See the Chrome DevTools docs where this approach [is documented](https://developer.chrome.com/docs/extensions/how-to/devtools/extend-devtools#evaluated-scripts-to-devtools). + +It creates a connection to the background page using `chrome.runtime.connect` with the name `'tab'` when it receives the first message from the injected page script. diff --git a/extension/edge/manifest.json b/extension/edge/manifest.json index 00fb14e6..8aa5365c 100644 --- a/extension/edge/manifest.json +++ b/extension/edge/manifest.json @@ -1,28 +1,22 @@ { - "version": "3.1.6", + "version": "3.2.4", "name": "Redux DevTools", "description": "Redux DevTools for debugging application's state changes.", "homepage_url": "https://github.com/reduxjs/redux-devtools", - "manifest_version": 2, - "page_action": { + "manifest_version": 3, + "action": { "default_icon": "img/logo/gray.png", "default_title": "Redux DevTools", - "default_popup": "window.html#popup" + "default_popup": "devpanel.html#popup" }, "commands": { - "devtools-left": { - "description": "DevTools window to left" - }, - "devtools-right": { - "description": "DevTools window to right" - }, - "devtools-bottom": { - "description": "DevTools window to bottom" + "devtools-window": { + "description": "DevTools window" }, "devtools-remote": { "description": "Remote DevTools" }, - "_execute_page_action": { + "_execute_action": { "suggested_key": { "default": "Ctrl+Shift+E" } @@ -34,34 +28,35 @@ "128": "img/logo/128x128.png" }, "options_ui": { - "page": "options.html", - "chrome_style": true + "page": "options.html" }, "background": { - "scripts": ["background.bundle.js"], - "persistent": false + "service_worker": "background.bundle.js" }, "content_scripts": [ { "matches": [""], "exclude_globs": ["https://www.google*"], - "js": ["content.bundle.js", "pagewrap.bundle.js"], + "js": ["content.bundle.js"], "run_at": "document_start", "all_frames": true + }, + { + "matches": [""], + "exclude_globs": ["https://www.google*"], + "js": ["page.bundle.js"], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" } ], "devtools_page": "devtools.html", - "web_accessible_resources": ["page.bundle.js"], "externally_connectable": { "ids": ["*"] }, - "permissions": [ - "notifications", - "contextMenus", - "storage", - "file:///*", - "http://*/*", - "https://*/*" - ], - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" + "permissions": ["notifications", "contextMenus", "storage"], + "host_permissions": ["file:///*", "http://*/*", "https://*/*"], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;" + } } diff --git a/extension/firefox/manifest.json b/extension/firefox/manifest.json index c19b76e8..65ec7fbb 100644 --- a/extension/firefox/manifest.json +++ b/extension/firefox/manifest.json @@ -1,29 +1,22 @@ { - "version": "3.1.6", + "version": "3.2.4", "name": "Redux DevTools", - "manifest_version": 2, + "manifest_version": 3, "description": "Redux Developer Tools for debugging application state changes.", "homepage_url": "https://github.com/reduxjs/redux-devtools", - "applications": { + "browser_specific_settings": { "gecko": { - "id": "extension@redux.devtools", - "strict_min_version": "54.0" + "id": "extension@redux.devtools" } }, - "page_action": { + "action": { "default_icon": "img/logo/38x38.png", "default_title": "Redux DevTools", - "default_popup": "window.html#popup" + "default_popup": "devpanel.html#popup" }, "commands": { - "devtools-left": { - "description": "DevTools window to left" - }, - "devtools-right": { - "description": "DevTools window to right" - }, - "devtools-bottom": { - "description": "DevTools window to bottom" + "devtools-window": { + "description": "DevTools window" }, "devtools-remote": { "description": "Remote DevTools" @@ -43,21 +36,22 @@ "content_scripts": [ { "matches": [""], - "js": ["content.bundle.js", "pagewrap.bundle.js"], + "js": ["content.bundle.js"], "run_at": "document_start", "all_frames": true + }, + { + "matches": [""], + "js": ["page.bundle.js"], + "run_at": "document_start", + "all_frames": true, + "world": "MAIN" } ], "devtools_page": "devtools.html", - "web_accessible_resources": ["page.bundle.js"], - "permissions": [ - "notifications", - "contextMenus", - "tabs", - "storage", - "file:///*", - "http://*/*", - "https://*/*" - ], - "content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self' data:;" + "permissions": ["notifications", "contextMenus", "tabs", "storage"], + "host_permissions": ["file:///*", "http://*/*", "https://*/*"], + "content_security_policy": { + "extension_pages": "script-src 'self'; object-src 'self'; img-src 'self' data:;" + } } diff --git a/extension/package.json b/extension/package.json index 7cab99a3..ad3fc23f 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "remotedev-redux-devtools-extension", - "version": "3.1.9", + "version": "3.2.4", "description": "Redux Developer Tools for debugging application state changes.", "homepage": "https://github.com/reduxjs/redux-devtools/tree/master/extension", "license": "MIT", @@ -23,62 +23,63 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@babel/polyfill": "^7.12.1", - "@emotion/react": "^11.11.4", - "@redux-devtools/app": "^6.0.1", - "@redux-devtools/core": "^4.0.0", - "@redux-devtools/instrument": "^2.1.0", - "@redux-devtools/serialize": "^0.4.1", - "@redux-devtools/slider-monitor": "^5.0.1", - "@redux-devtools/ui": "^1.3.2", - "@redux-devtools/utils": "^3.0.0", + "@emotion/react": "^11.13.3", + "@redux-devtools/app": "workspace:^", + "@redux-devtools/core": "workspace:^", + "@redux-devtools/instrument": "workspace:^", + "@redux-devtools/serialize": "workspace:^", + "@redux-devtools/slider-monitor": "workspace:^", + "@redux-devtools/ui": "workspace:^", + "@redux-devtools/utils": "workspace:^", + "@reduxjs/toolkit": "^2.2.7", "@types/jsan": "^3.1.5", "jsan": "^3.1.14", "localforage": "^1.10.0", - "lodash": "^4.17.21", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-icons": "^5.0.1", - "react-is": "^18.2.0", - "react-json-tree": "^0.19.0", - "react-redux": "^8.1.3", - "redux": "^4.2.1", + "lodash-es": "^4.17.21", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-icons": "^5.3.0", + "react-is": "^18.3.1", + "react-json-tree": "workspace:^", + "react-redux": "^9.1.2", + "redux": "^5.0.1", "redux-persist": "^6.0.0", "styled-components": "^5.3.11" }, "devDependencies": { - "@babel/core": "^7.24.3", - "@babel/preset-env": "^7.24.3", - "@babel/preset-react": "^7.24.1", - "@babel/preset-typescript": "^7.24.1", - "@babel/register": "^7.23.7", - "@testing-library/jest-dom": "^6.4.2", - "@testing-library/react": "^14.2.2", - "@types/chrome": "^0.0.263", - "@types/lodash": "^4.17.0", - "@types/react": "^18.2.72", - "@types/react-dom": "^18.2.22", + "@babel/core": "^7.25.2", + "@babel/preset-env": "^7.25.4", + "@babel/preset-react": "^7.24.7", + "@babel/preset-typescript": "^7.24.7", + "@babel/register": "^7.24.6", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", + "@types/chrome": "^0.0.270", + "@types/lodash-es": "^4.17.12", + "@types/react": "^18.3.5", + "@types/react-dom": "^18.3.0", "@types/styled-components": "^5.1.34", - "chromedriver": "^118.0.1", + "chromedriver": "^126.0.5", "cross-env": "^7.0.3", - "electron": "^27.3.7", - "esbuild": "^0.20.2", + "electron": "^31.4.0", + "esbuild": "^0.23.1", "eslint": "^8.57.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", - "eslint-plugin-react-hooks": "^4.6.0", - "immutable": "^4.3.5", + "eslint-plugin-jsx-a11y": "^6.9.0", + "eslint-plugin-react": "^7.35.0", + "eslint-plugin-react-hooks": "^4.6.2", + "immutable": "^4.3.7", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "pug": "^3.0.2", - "rimraf": "^5.0.5", - "selenium-webdriver": "^4.18.1", + "pug": "^3.0.3", + "rimraf": "^6.0.1", + "selenium-webdriver": "^4.24.0", "sinon-chrome": "^3.0.1", - "ts-jest": "^29.1.2", - "typescript": "~5.3.3", - "webpack": "^5.91.0", + "ts-jest": "^29.2.5", + "typescript": "~5.5.4", + "webpack": "^5.94.0", "webpack-cli": "^5.1.4" } } diff --git a/extension/src/app/Actions.tsx b/extension/src/app/Actions.tsx index 00abd2b9..656bb6d6 100644 --- a/extension/src/app/Actions.tsx +++ b/extension/src/app/Actions.tsx @@ -18,7 +18,7 @@ import { TopButtons, } from '@redux-devtools/app'; import { GoBroadcast } from 'react-icons/go'; -import { MdBorderBottom, MdBorderLeft, MdBorderRight } from 'react-icons/md'; +import { MdOutlineWindow } from 'react-icons/md'; import type { Position } from '../pageScript/api/openWindow'; import type { SingleMessage } from '../background/store/apiMiddleware'; @@ -29,11 +29,7 @@ interface OwnProps { } type Props = StateProps & DispatchProps & OwnProps; -declare global { - interface Window { - isElectron?: boolean; - } -} +const isElectron = navigator.userAgent.includes('Electron'); function sendMessage(message: SingleMessage) { chrome.runtime.sendMessage(message); @@ -98,34 +94,16 @@ class Actions extends Component { )} - {!window.isElectron && position !== '#left' && ( + {!isElectron && ( )} - {!window.isElectron && position !== '#right' && ( - - )} - {!window.isElectron && position !== '#bottom' && ( - - )} - {!window.isElectron && ( + {!isElectron && (