mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-22 09:36:43 +03:00
Merge branch 'main' into main
This commit is contained in:
commit
ef3f1c558d
2
.github/workflows/CI.yml
vendored
2
.github/workflows/CI.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- uses: nrwl/nx-set-shas@v4
|
- uses: nrwl/nx-set-shas@v4
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
||||||
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,4 +9,4 @@ coverage
|
||||||
.idea
|
.idea
|
||||||
.eslintcache
|
.eslintcache
|
||||||
!packages/redux-devtools-slider-monitor/examples/todomvc/dist/index.html
|
!packages/redux-devtools-slider-monitor/examples/todomvc/dist/index.html
|
||||||
.nx/cache
|
.nx
|
||||||
|
|
4
eslint.js.config.base.mjs
Normal file
4
eslint.js.config.base.mjs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import eslint from '@eslint/js';
|
||||||
|
import eslintConfigPrettier from 'eslint-config-prettier';
|
||||||
|
|
||||||
|
export default [eslint.configs.recommended, eslintConfigPrettier];
|
55
eslint.ts.config.base.mjs
Normal file
55
eslint.ts.config.base.mjs
Normal file
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
64
eslint.ts.jest.config.base.mjs
Normal file
64
eslint.ts.jest.config.base.mjs
Normal file
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
89
eslint.ts.react.config.base.mjs
Normal file
89
eslint.ts.react.config.base.mjs
Normal file
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
85
eslint.ts.react.jest.config.base.mjs
Normal file
85
eslint.ts.react.jest.config.base.mjs
Normal file
|
@ -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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"parser": "@babel/eslint-parser"
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,42 @@
|
||||||
# remotedev-redux-devtools-extension
|
# 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
|
## 3.1.9
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
|
@ -5,7 +5,7 @@ import pug from 'pug';
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const prod = !args.includes('--dev');
|
const prod = !args.includes('--dev');
|
||||||
|
|
||||||
const commonEsbuildOptions = {
|
await esbuild.build({
|
||||||
bundle: true,
|
bundle: true,
|
||||||
logLevel: 'info',
|
logLevel: 'info',
|
||||||
outdir: 'dist',
|
outdir: 'dist',
|
||||||
|
@ -15,40 +15,24 @@ const commonEsbuildOptions = {
|
||||||
'process.env.NODE_ENV': prod ? '"production"' : '"development"',
|
'process.env.NODE_ENV': prod ? '"production"' : '"development"',
|
||||||
'process.env.BABEL_ENV': prod ? '"production"' : '"development"',
|
'process.env.BABEL_ENV': prod ? '"production"' : '"development"',
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
await esbuild.build({
|
|
||||||
...commonEsbuildOptions,
|
|
||||||
entryPoints: [
|
entryPoints: [
|
||||||
{ out: 'background.bundle', in: 'src/background/index.ts' },
|
{ out: 'background.bundle', in: 'src/background/index.ts' },
|
||||||
{ out: 'options.bundle', in: 'src/options/index.tsx' },
|
{ 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: 'remote.bundle', in: 'src/remote/index.tsx' },
|
||||||
{ out: 'devpanel.bundle', in: 'src/devpanel/index.tsx' },
|
{ out: 'devpanel.bundle', in: 'src/devpanel/index.tsx' },
|
||||||
{ out: 'devtools.bundle', in: 'src/devtools/index.ts' },
|
{ out: 'devtools.bundle', in: 'src/devtools/index.ts' },
|
||||||
{ out: 'content.bundle', in: 'src/contentScript/index.ts' },
|
{ out: 'content.bundle', in: 'src/contentScript/index.ts' },
|
||||||
{ out: 'page.bundle', in: 'src/pageScript/index.ts' },
|
{ out: 'page.bundle', in: 'src/pageScript/index.ts' },
|
||||||
...(prod ? [] : [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }]),
|
|
||||||
],
|
],
|
||||||
loader: {
|
loader: {
|
||||||
'.woff2': 'file',
|
'.woff2': 'file',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (prod) {
|
|
||||||
await esbuild.build({
|
|
||||||
...commonEsbuildOptions,
|
|
||||||
entryPoints: [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }],
|
|
||||||
loader: {
|
|
||||||
'.js': 'text',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
|
|
||||||
console.log('Creating HTML files...');
|
console.log('Creating HTML files...');
|
||||||
const htmlFiles = ['devpanel', 'devtools', 'options', 'remote', 'window'];
|
const htmlFiles = ['devpanel', 'devtools', 'options', 'remote'];
|
||||||
for (const htmlFile of htmlFiles) {
|
for (const htmlFile of htmlFiles) {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
`dist/${htmlFile}.html`,
|
`dist/${htmlFile}.html`,
|
||||||
|
|
|
@ -1,28 +1,22 @@
|
||||||
{
|
{
|
||||||
"version": "3.1.6",
|
"version": "3.2.4",
|
||||||
"name": "Redux DevTools",
|
"name": "Redux DevTools",
|
||||||
"description": "Redux DevTools for debugging application's state changes.",
|
"description": "Redux DevTools for debugging application's state changes.",
|
||||||
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
||||||
"manifest_version": 2,
|
"manifest_version": 3,
|
||||||
"page_action": {
|
"action": {
|
||||||
"default_icon": "img/logo/gray.png",
|
"default_icon": "img/logo/gray.png",
|
||||||
"default_title": "Redux DevTools",
|
"default_title": "Redux DevTools",
|
||||||
"default_popup": "window.html#popup"
|
"default_popup": "devpanel.html#popup"
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"devtools-left": {
|
"devtools-window": {
|
||||||
"description": "DevTools window to left"
|
"description": "DevTools window"
|
||||||
},
|
|
||||||
"devtools-right": {
|
|
||||||
"description": "DevTools window to right"
|
|
||||||
},
|
|
||||||
"devtools-bottom": {
|
|
||||||
"description": "DevTools window to bottom"
|
|
||||||
},
|
},
|
||||||
"devtools-remote": {
|
"devtools-remote": {
|
||||||
"description": "Remote DevTools"
|
"description": "Remote DevTools"
|
||||||
},
|
},
|
||||||
"_execute_page_action": {
|
"_execute_action": {
|
||||||
"suggested_key": {
|
"suggested_key": {
|
||||||
"default": "Ctrl+Shift+E"
|
"default": "Ctrl+Shift+E"
|
||||||
}
|
}
|
||||||
|
@ -34,36 +28,37 @@
|
||||||
"128": "img/logo/128x128.png"
|
"128": "img/logo/128x128.png"
|
||||||
},
|
},
|
||||||
"options_ui": {
|
"options_ui": {
|
||||||
"page": "options.html",
|
"page": "options.html"
|
||||||
"chrome_style": true
|
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.bundle.js"],
|
"service_worker": "background.bundle.js"
|
||||||
"persistent": false
|
|
||||||
},
|
},
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["<all_urls>"],
|
"matches": ["<all_urls>"],
|
||||||
"exclude_globs": ["https://www.google*"],
|
"exclude_globs": ["https://www.google*"],
|
||||||
"js": ["content.bundle.js", "pagewrap.bundle.js"],
|
"js": ["content.bundle.js"],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matches": ["<all_urls>"],
|
||||||
|
"exclude_globs": ["https://www.google*"],
|
||||||
|
"js": ["page.bundle.js"],
|
||||||
|
"run_at": "document_start",
|
||||||
|
"all_frames": true,
|
||||||
|
"world": "MAIN"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"devtools_page": "devtools.html",
|
"devtools_page": "devtools.html",
|
||||||
"web_accessible_resources": ["page.bundle.js"],
|
|
||||||
"externally_connectable": {
|
"externally_connectable": {
|
||||||
"ids": ["*"]
|
"ids": ["*"]
|
||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": ["notifications", "contextMenus", "storage"],
|
||||||
"notifications",
|
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
|
||||||
"contextMenus",
|
"content_security_policy": {
|
||||||
"storage",
|
"extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;"
|
||||||
"file:///*",
|
},
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
],
|
|
||||||
"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",
|
"update_url": "https://clients2.google.com/service/update2/crx",
|
||||||
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdJEPwY92xUACA9CcDBDBmbdbp8Ap3cKQ0DJTUuVQvqb4FQAv8RtKY3iUjGvdwuAcSJQIZwHXcP2aNDH3TiFik/NhRK2GRW8X3OZyTdkuDueABGP2KEX8q1WQDgjX/rPIinGYztUrvoICw/UerMPwNW62jwGoVU3YhAGf+15CgX2Y6a4tppnf/+1mPedKPidh0RsM+aJY98rX+r1SPAHPcGzMjocLkqcT75DZBXer8VQN14tOOzRCd6T6oy7qm7eWru8lJwcY66qMQvhk0osqEod2G3nA7aTWpmqPFS66VEiecP9PgZlp8gQdgZ3dFhA62exydlD55JuRhiMIR63yQIDAQAB"
|
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdJEPwY92xUACA9CcDBDBmbdbp8Ap3cKQ0DJTUuVQvqb4FQAv8RtKY3iUjGvdwuAcSJQIZwHXcP2aNDH3TiFik/NhRK2GRW8X3OZyTdkuDueABGP2KEX8q1WQDgjX/rPIinGYztUrvoICw/UerMPwNW62jwGoVU3YhAGf+15CgX2Y6a4tppnf/+1mPedKPidh0RsM+aJY98rX+r1SPAHPcGzMjocLkqcT75DZBXer8VQN14tOOzRCd6T6oy7qm7eWru8lJwcY66qMQvhk0osqEod2G3nA7aTWpmqPFS66VEiecP9PgZlp8gQdgZ3dFhA62exydlD55JuRhiMIR63yQIDAQAB"
|
||||||
}
|
}
|
||||||
|
|
37
extension/docs/Architecture.md
Normal file
37
extension/docs/Architecture.md
Normal file
|
@ -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.
|
|
@ -1,28 +1,22 @@
|
||||||
{
|
{
|
||||||
"version": "3.1.6",
|
"version": "3.2.4",
|
||||||
"name": "Redux DevTools",
|
"name": "Redux DevTools",
|
||||||
"description": "Redux DevTools for debugging application's state changes.",
|
"description": "Redux DevTools for debugging application's state changes.",
|
||||||
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
||||||
"manifest_version": 2,
|
"manifest_version": 3,
|
||||||
"page_action": {
|
"action": {
|
||||||
"default_icon": "img/logo/gray.png",
|
"default_icon": "img/logo/gray.png",
|
||||||
"default_title": "Redux DevTools",
|
"default_title": "Redux DevTools",
|
||||||
"default_popup": "window.html#popup"
|
"default_popup": "devpanel.html#popup"
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"devtools-left": {
|
"devtools-window": {
|
||||||
"description": "DevTools window to left"
|
"description": "DevTools window"
|
||||||
},
|
|
||||||
"devtools-right": {
|
|
||||||
"description": "DevTools window to right"
|
|
||||||
},
|
|
||||||
"devtools-bottom": {
|
|
||||||
"description": "DevTools window to bottom"
|
|
||||||
},
|
},
|
||||||
"devtools-remote": {
|
"devtools-remote": {
|
||||||
"description": "Remote DevTools"
|
"description": "Remote DevTools"
|
||||||
},
|
},
|
||||||
"_execute_page_action": {
|
"_execute_action": {
|
||||||
"suggested_key": {
|
"suggested_key": {
|
||||||
"default": "Ctrl+Shift+E"
|
"default": "Ctrl+Shift+E"
|
||||||
}
|
}
|
||||||
|
@ -34,34 +28,35 @@
|
||||||
"128": "img/logo/128x128.png"
|
"128": "img/logo/128x128.png"
|
||||||
},
|
},
|
||||||
"options_ui": {
|
"options_ui": {
|
||||||
"page": "options.html",
|
"page": "options.html"
|
||||||
"chrome_style": true
|
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.bundle.js"],
|
"service_worker": "background.bundle.js"
|
||||||
"persistent": false
|
|
||||||
},
|
},
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["<all_urls>"],
|
"matches": ["<all_urls>"],
|
||||||
"exclude_globs": ["https://www.google*"],
|
"exclude_globs": ["https://www.google*"],
|
||||||
"js": ["content.bundle.js", "pagewrap.bundle.js"],
|
"js": ["content.bundle.js"],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matches": ["<all_urls>"],
|
||||||
|
"exclude_globs": ["https://www.google*"],
|
||||||
|
"js": ["page.bundle.js"],
|
||||||
|
"run_at": "document_start",
|
||||||
|
"all_frames": true,
|
||||||
|
"world": "MAIN"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"devtools_page": "devtools.html",
|
"devtools_page": "devtools.html",
|
||||||
"web_accessible_resources": ["page.bundle.js"],
|
|
||||||
"externally_connectable": {
|
"externally_connectable": {
|
||||||
"ids": ["*"]
|
"ids": ["*"]
|
||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": ["notifications", "contextMenus", "storage"],
|
||||||
"notifications",
|
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
|
||||||
"contextMenus",
|
"content_security_policy": {
|
||||||
"storage",
|
"extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;"
|
||||||
"file:///*",
|
}
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
],
|
|
||||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,22 @@
|
||||||
{
|
{
|
||||||
"version": "3.1.6",
|
"version": "3.2.4",
|
||||||
"name": "Redux DevTools",
|
"name": "Redux DevTools",
|
||||||
"manifest_version": 2,
|
"manifest_version": 3,
|
||||||
"description": "Redux Developer Tools for debugging application state changes.",
|
"description": "Redux Developer Tools for debugging application state changes.",
|
||||||
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
||||||
"applications": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
"id": "extension@redux.devtools",
|
"id": "extension@redux.devtools"
|
||||||
"strict_min_version": "54.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"page_action": {
|
"action": {
|
||||||
"default_icon": "img/logo/38x38.png",
|
"default_icon": "img/logo/38x38.png",
|
||||||
"default_title": "Redux DevTools",
|
"default_title": "Redux DevTools",
|
||||||
"default_popup": "window.html#popup"
|
"default_popup": "devpanel.html#popup"
|
||||||
},
|
},
|
||||||
"commands": {
|
"commands": {
|
||||||
"devtools-left": {
|
"devtools-window": {
|
||||||
"description": "DevTools window to left"
|
"description": "DevTools window"
|
||||||
},
|
|
||||||
"devtools-right": {
|
|
||||||
"description": "DevTools window to right"
|
|
||||||
},
|
|
||||||
"devtools-bottom": {
|
|
||||||
"description": "DevTools window to bottom"
|
|
||||||
},
|
},
|
||||||
"devtools-remote": {
|
"devtools-remote": {
|
||||||
"description": "Remote DevTools"
|
"description": "Remote DevTools"
|
||||||
|
@ -43,21 +36,22 @@
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["<all_urls>"],
|
"matches": ["<all_urls>"],
|
||||||
"js": ["content.bundle.js", "pagewrap.bundle.js"],
|
"js": ["content.bundle.js"],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matches": ["<all_urls>"],
|
||||||
|
"js": ["page.bundle.js"],
|
||||||
|
"run_at": "document_start",
|
||||||
|
"all_frames": true,
|
||||||
|
"world": "MAIN"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"devtools_page": "devtools.html",
|
"devtools_page": "devtools.html",
|
||||||
"web_accessible_resources": ["page.bundle.js"],
|
"permissions": ["notifications", "contextMenus", "tabs", "storage"],
|
||||||
"permissions": [
|
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
|
||||||
"notifications",
|
"content_security_policy": {
|
||||||
"contextMenus",
|
"extension_pages": "script-src 'self'; object-src 'self'; img-src 'self' data:;"
|
||||||
"tabs",
|
}
|
||||||
"storage",
|
|
||||||
"file:///*",
|
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
],
|
|
||||||
"content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self' data:;"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "remotedev-redux-devtools-extension",
|
"name": "remotedev-redux-devtools-extension",
|
||||||
"version": "3.1.9",
|
"version": "3.2.4",
|
||||||
"description": "Redux Developer Tools for debugging application state changes.",
|
"description": "Redux Developer Tools for debugging application state changes.",
|
||||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/extension",
|
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/extension",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -23,62 +23,63 @@
|
||||||
"type-check": "tsc --noEmit"
|
"type-check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.12.1",
|
"@emotion/react": "^11.13.3",
|
||||||
"@emotion/react": "^11.11.4",
|
"@redux-devtools/app": "workspace:^",
|
||||||
"@redux-devtools/app": "^6.0.1",
|
"@redux-devtools/core": "workspace:^",
|
||||||
"@redux-devtools/core": "^4.0.0",
|
"@redux-devtools/instrument": "workspace:^",
|
||||||
"@redux-devtools/instrument": "^2.1.0",
|
"@redux-devtools/serialize": "workspace:^",
|
||||||
"@redux-devtools/serialize": "^0.4.1",
|
"@redux-devtools/slider-monitor": "workspace:^",
|
||||||
"@redux-devtools/slider-monitor": "^5.0.1",
|
"@redux-devtools/ui": "workspace:^",
|
||||||
"@redux-devtools/ui": "^1.3.2",
|
"@redux-devtools/utils": "workspace:^",
|
||||||
"@redux-devtools/utils": "^3.0.0",
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
"@types/jsan": "^3.1.5",
|
"@types/jsan": "^3.1.5",
|
||||||
"jsan": "^3.1.14",
|
"jsan": "^3.1.14",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.3.0",
|
||||||
"react-is": "^18.2.0",
|
"react-is": "^18.3.1",
|
||||||
"react-json-tree": "^0.19.0",
|
"react-json-tree": "workspace:^",
|
||||||
"react-redux": "^8.1.3",
|
"react-redux": "^9.1.2",
|
||||||
"redux": "^4.2.1",
|
"redux": "^5.0.1",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"styled-components": "^5.3.11"
|
"styled-components": "^5.3.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.3",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-env": "^7.24.3",
|
"@babel/preset-env": "^7.25.4",
|
||||||
"@babel/preset-react": "^7.24.1",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@babel/preset-typescript": "^7.24.1",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@babel/register": "^7.23.7",
|
"@babel/register": "^7.24.6",
|
||||||
"@testing-library/jest-dom": "^6.4.2",
|
"@testing-library/dom": "^10.4.0",
|
||||||
"@testing-library/react": "^14.2.2",
|
"@testing-library/jest-dom": "^6.5.0",
|
||||||
"@types/chrome": "^0.0.263",
|
"@testing-library/react": "^16.0.1",
|
||||||
"@types/lodash": "^4.17.0",
|
"@types/chrome": "^0.0.270",
|
||||||
"@types/react": "^18.2.72",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/react-dom": "^18.2.22",
|
"@types/react": "^18.3.5",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/styled-components": "^5.1.34",
|
"@types/styled-components": "^5.1.34",
|
||||||
"chromedriver": "^118.0.1",
|
"chromedriver": "^126.0.5",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"electron": "^27.3.7",
|
"electron": "^31.4.0",
|
||||||
"esbuild": "^0.20.2",
|
"esbuild": "^0.23.1",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.9.0",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.35.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"immutable": "^4.3.5",
|
"immutable": "^4.3.7",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"pug": "^3.0.2",
|
"pug": "^3.0.3",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^6.0.1",
|
||||||
"selenium-webdriver": "^4.18.1",
|
"selenium-webdriver": "^4.24.0",
|
||||||
"sinon-chrome": "^3.0.1",
|
"sinon-chrome": "^3.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "~5.3.3",
|
"typescript": "~5.5.4",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.94.0",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
TopButtons,
|
TopButtons,
|
||||||
} from '@redux-devtools/app';
|
} from '@redux-devtools/app';
|
||||||
import { GoBroadcast } from 'react-icons/go';
|
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 { Position } from '../pageScript/api/openWindow';
|
||||||
import type { SingleMessage } from '../background/store/apiMiddleware';
|
import type { SingleMessage } from '../background/store/apiMiddleware';
|
||||||
|
|
||||||
|
@ -29,11 +29,7 @@ interface OwnProps {
|
||||||
}
|
}
|
||||||
type Props = StateProps & DispatchProps & OwnProps;
|
type Props = StateProps & DispatchProps & OwnProps;
|
||||||
|
|
||||||
declare global {
|
const isElectron = navigator.userAgent.includes('Electron');
|
||||||
interface Window {
|
|
||||||
isElectron?: boolean;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMessage(message: SingleMessage) {
|
function sendMessage(message: SingleMessage) {
|
||||||
chrome.runtime.sendMessage(message);
|
chrome.runtime.sendMessage(message);
|
||||||
|
@ -98,34 +94,16 @@ class Actions extends Component<Props> {
|
||||||
<DispatcherButton dispatcherIsOpen={this.props.dispatcherIsOpen} />
|
<DispatcherButton dispatcherIsOpen={this.props.dispatcherIsOpen} />
|
||||||
)}
|
)}
|
||||||
<Divider />
|
<Divider />
|
||||||
{!window.isElectron && position !== '#left' && (
|
{!isElectron && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.openWindow('left');
|
this.openWindow('window');
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MdBorderLeft />
|
<MdOutlineWindow />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!window.isElectron && position !== '#right' && (
|
{!isElectron && (
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
this.openWindow('right');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdBorderRight />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{!window.isElectron && position !== '#bottom' && (
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
this.openWindow('bottom');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MdBorderBottom />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{!window.isElectron && (
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.openWindow('remote');
|
this.openWindow('remote');
|
||||||
|
|
|
@ -2,29 +2,23 @@ import openDevToolsWindow, { DevToolsPosition } from './openWindow';
|
||||||
|
|
||||||
export function createMenu() {
|
export function createMenu() {
|
||||||
const menus = [
|
const menus = [
|
||||||
{ id: 'devtools-left', title: 'To left' },
|
{ id: 'devtools-window', title: 'Open in a window' },
|
||||||
{ id: 'devtools-right', title: 'To right' },
|
|
||||||
{ id: 'devtools-bottom', title: 'To bottom' },
|
|
||||||
{
|
|
||||||
id: 'devtools-panel',
|
|
||||||
title: 'Open in a panel (enable in browser settings)',
|
|
||||||
},
|
|
||||||
{ id: 'devtools-remote', title: 'Open Remote DevTools' },
|
{ id: 'devtools-remote', title: 'Open Remote DevTools' },
|
||||||
];
|
];
|
||||||
|
|
||||||
let shortcuts: { [commandName: string]: string | undefined } = {};
|
let shortcuts: { [commandName: string]: string | undefined } = {};
|
||||||
chrome.commands.getAll((commands) => {
|
chrome.commands.getAll((commands) => {
|
||||||
commands.forEach(({ name, shortcut }) => {
|
for (const { name, shortcut } of commands) {
|
||||||
shortcuts[name!] = shortcut;
|
shortcuts[name!] = shortcut;
|
||||||
});
|
}
|
||||||
|
|
||||||
menus.forEach(({ id, title }) => {
|
for (const { id, title } of menus) {
|
||||||
chrome.contextMenus.create({
|
chrome.contextMenus.create({
|
||||||
id: id,
|
id: id,
|
||||||
title: title + (shortcuts[id] ? ' (' + shortcuts[id] + ')' : ''),
|
title: title + (shortcuts[id] ? ' (' + shortcuts[id] + ')' : ''),
|
||||||
contexts: ['all'],
|
contexts: ['all'],
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,23 @@
|
||||||
import '../chromeApiMock';
|
import '../chromeApiMock';
|
||||||
import { Store } from 'redux';
|
import configureStore from './store/backgroundStore';
|
||||||
import configureStore, { BackgroundAction } from './store/backgroundStore';
|
|
||||||
import openDevToolsWindow, { DevToolsPosition } from './openWindow';
|
import openDevToolsWindow, { DevToolsPosition } from './openWindow';
|
||||||
import { createMenu, removeMenu } from './contextMenus';
|
import { createMenu, removeMenu } from './contextMenus';
|
||||||
import syncOptions from '../options/syncOptions';
|
import { getOptions } from '../options/syncOptions';
|
||||||
import { BackgroundState } from './store/backgroundReducer';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
store: Store<BackgroundState, BackgroundAction>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expose the extension's store globally to access it from the windows
|
// Expose the extension's store globally to access it from the windows
|
||||||
// via chrome.runtime.getBackgroundPage
|
// via chrome.runtime.getBackgroundPage
|
||||||
window.store = configureStore();
|
export const store = configureStore();
|
||||||
|
|
||||||
// Listen for keyboard shortcuts
|
// Listen for keyboard shortcuts
|
||||||
chrome.commands.onCommand.addListener((shortcut) => {
|
chrome.commands.onCommand.addListener((shortcut) => {
|
||||||
openDevToolsWindow(shortcut as DevToolsPosition);
|
openDevToolsWindow(shortcut as DevToolsPosition);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create the context menu when installed
|
// Disable the action by default and create the context menu when installed
|
||||||
chrome.runtime.onInstalled.addListener(() => {
|
chrome.runtime.onInstalled.addListener(() => {
|
||||||
syncOptions().get((option) => {
|
chrome.action.disable();
|
||||||
|
|
||||||
|
getOptions((option) => {
|
||||||
if (option.showContextMenus) createMenu();
|
if (option.showContextMenus) createMenu();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { LIFTED_ACTION } from '@redux-devtools/app';
|
import { LIFTED_ACTION } from '@redux-devtools/app';
|
||||||
|
import { store } from './index';
|
||||||
|
|
||||||
export function getReport(
|
export function getReport(
|
||||||
reportId: string,
|
reportId: string,
|
||||||
|
@ -24,7 +25,7 @@ export function getReport(
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
const { payload, preloadedState } = json;
|
const { payload, preloadedState } = json;
|
||||||
if (!payload) return;
|
if (!payload) return;
|
||||||
window.store.dispatch({
|
store.dispatch({
|
||||||
type: LIFTED_ACTION,
|
type: LIFTED_ACTION,
|
||||||
message: 'IMPORT',
|
message: 'IMPORT',
|
||||||
state: JSON.stringify({ payload, preloadedState }),
|
state: JSON.stringify({ payload, preloadedState }),
|
||||||
|
|
|
@ -1,83 +1,34 @@
|
||||||
export type DevToolsPosition =
|
export type DevToolsPosition = 'devtools-window' | 'devtools-remote';
|
||||||
| 'devtools-left'
|
|
||||||
| 'devtools-right'
|
|
||||||
| 'devtools-bottom'
|
|
||||||
| 'devtools-panel'
|
|
||||||
| 'devtools-remote';
|
|
||||||
|
|
||||||
let windows: { [K in DevToolsPosition]?: number } = {};
|
let windows: { [K in DevToolsPosition]?: number } = {};
|
||||||
let lastPosition: DevToolsPosition | null = null;
|
|
||||||
|
|
||||||
export default function openDevToolsWindow(position: DevToolsPosition) {
|
export default function openDevToolsWindow(position: DevToolsPosition) {
|
||||||
function popWindow(
|
|
||||||
action: string,
|
|
||||||
url: string,
|
|
||||||
customOptions: chrome.windows.CreateData & chrome.windows.UpdateInfo,
|
|
||||||
) {
|
|
||||||
function focusIfExist(callback: () => void) {
|
|
||||||
if (!windows[position]) {
|
if (!windows[position]) {
|
||||||
callback();
|
createWindow(position);
|
||||||
lastPosition = position;
|
|
||||||
} else {
|
} else {
|
||||||
let params = { focused: true };
|
chrome.windows.update(windows[position]!, { focused: true }, () => {
|
||||||
if (lastPosition !== position && position !== 'devtools-panel') {
|
if (chrome.runtime.lastError) createWindow(position);
|
||||||
params = { ...params, ...customOptions };
|
|
||||||
}
|
|
||||||
chrome.windows.update(windows[position]!, params, () => {
|
|
||||||
lastPosition = null;
|
|
||||||
if (chrome.runtime.lastError) callback();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
focusIfExist(() => {
|
function createWindow(position: DevToolsPosition) {
|
||||||
let options: chrome.windows.CreateData = {
|
const url = chrome.runtime.getURL(getPath(position));
|
||||||
type: 'popup',
|
chrome.windows.create({ type: 'popup', url }, (win) => {
|
||||||
...customOptions,
|
|
||||||
};
|
|
||||||
if (action === 'open') {
|
|
||||||
options.url = chrome.extension.getURL(
|
|
||||||
url + '#' + position.substr(position.indexOf('-') + 1),
|
|
||||||
);
|
|
||||||
chrome.windows.create(options, (win) => {
|
|
||||||
windows[position] = win!.id;
|
windows[position] = win!.id;
|
||||||
if (navigator.userAgent.indexOf('Firefox') !== -1) {
|
if (navigator.userAgent.indexOf('Firefox') !== -1) {
|
||||||
chrome.windows.update(win!.id!, {
|
chrome.windows.update(win!.id!, { focused: true });
|
||||||
focused: true,
|
|
||||||
...customOptions,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
function getPath(position: DevToolsPosition) {
|
||||||
|
switch (position) {
|
||||||
let params: chrome.windows.CreateData & chrome.windows.UpdateInfo = {
|
case 'devtools-window':
|
||||||
left: 0,
|
return 'devpanel.html';
|
||||||
top: 0,
|
case 'devtools-remote':
|
||||||
width: 380,
|
return 'remote.html';
|
||||||
height: window.screen.availHeight,
|
default:
|
||||||
};
|
throw new Error(`Unrecognized position: ${position}`);
|
||||||
let url = 'window.html';
|
}
|
||||||
switch (position) {
|
|
||||||
case 'devtools-right':
|
|
||||||
params.left =
|
|
||||||
(window.screen as unknown as { availLeft: number }).availLeft +
|
|
||||||
window.screen.availWidth -
|
|
||||||
params.width!;
|
|
||||||
break;
|
|
||||||
case 'devtools-bottom':
|
|
||||||
params.height = 420;
|
|
||||||
params.top = window.screen.height - params.height;
|
|
||||||
params.width = window.screen.availWidth;
|
|
||||||
break;
|
|
||||||
case 'devtools-panel':
|
|
||||||
params.type = 'panel';
|
|
||||||
break;
|
|
||||||
case 'devtools-remote':
|
|
||||||
params = { width: 850, height: 600 };
|
|
||||||
url = 'remote.html';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
popWindow('open', url, params);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,10 @@ import {
|
||||||
TOGGLE_PERSIST,
|
TOGGLE_PERSIST,
|
||||||
UPDATE_STATE,
|
UPDATE_STATE,
|
||||||
} from '@redux-devtools/app';
|
} from '@redux-devtools/app';
|
||||||
import syncOptions, {
|
import type { Options, OptionsMessage } from '../../options/syncOptions';
|
||||||
Options,
|
|
||||||
OptionsMessage,
|
|
||||||
SyncOptions,
|
|
||||||
} from '../../options/syncOptions';
|
|
||||||
import openDevToolsWindow, { DevToolsPosition } from '../openWindow';
|
import openDevToolsWindow, { DevToolsPosition } from '../openWindow';
|
||||||
import { getReport } from '../logging';
|
import { getReport } from '../logging';
|
||||||
import { Action, Dispatch, MiddlewareAPI } from 'redux';
|
import { Action, Dispatch, Middleware } from 'redux';
|
||||||
import type {
|
import type {
|
||||||
ContentScriptToBackgroundMessage,
|
ContentScriptToBackgroundMessage,
|
||||||
SplitMessage,
|
SplitMessage,
|
||||||
|
@ -32,6 +28,7 @@ import { LiftedState } from '@redux-devtools/instrument';
|
||||||
import type { BackgroundAction, LiftedActionAction } from './backgroundStore';
|
import type { BackgroundAction, LiftedActionAction } from './backgroundStore';
|
||||||
import type { Position } from '../../pageScript/api/openWindow';
|
import type { Position } from '../../pageScript/api/openWindow';
|
||||||
import type { BackgroundState } from './backgroundReducer';
|
import type { BackgroundState } from './backgroundReducer';
|
||||||
|
import { store } from '../index';
|
||||||
|
|
||||||
interface TabMessageBase {
|
interface TabMessageBase {
|
||||||
readonly type: string;
|
readonly type: string;
|
||||||
|
@ -51,6 +48,11 @@ interface StopAction extends TabMessageBase {
|
||||||
readonly id?: never;
|
readonly id?: never;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface OptionsAction {
|
||||||
|
readonly type: 'OPTIONS';
|
||||||
|
readonly options: Options;
|
||||||
|
}
|
||||||
|
|
||||||
interface DispatchAction extends TabMessageBase {
|
interface DispatchAction extends TabMessageBase {
|
||||||
readonly type: 'DISPATCH';
|
readonly type: 'DISPATCH';
|
||||||
readonly action: AppDispatchAction;
|
readonly action: AppDispatchAction;
|
||||||
|
@ -151,7 +153,7 @@ interface SerializedStateMessage<S, A extends Action<string>> {
|
||||||
readonly committedState: boolean;
|
readonly committedState: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateStateRequest<S, A extends Action<string>> =
|
export type UpdateStateRequest<S, A extends Action<string>> =
|
||||||
| InitMessage<S, A>
|
| InitMessage<S, A>
|
||||||
| LiftedMessage
|
| LiftedMessage
|
||||||
| SerializedPartialStateMessage
|
| SerializedPartialStateMessage
|
||||||
|
@ -159,57 +161,72 @@ type UpdateStateRequest<S, A extends Action<string>> =
|
||||||
| SerializedActionMessage
|
| SerializedActionMessage
|
||||||
| SerializedStateMessage<S, A>;
|
| SerializedStateMessage<S, A>;
|
||||||
|
|
||||||
export interface EmptyUpdateStateAction {
|
|
||||||
readonly type: typeof UPDATE_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface UpdateStateAction<S, A extends Action<string>> {
|
interface UpdateStateAction<S, A extends Action<string>> {
|
||||||
readonly type: typeof UPDATE_STATE;
|
readonly type: typeof UPDATE_STATE;
|
||||||
request: UpdateStateRequest<S, A>;
|
request: UpdateStateRequest<S, A>;
|
||||||
readonly id: string | number;
|
readonly id: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SplitUpdateStateRequestStart<S, A extends Action<string>> = {
|
||||||
|
split: 'start';
|
||||||
|
} & Partial<UpdateStateRequest<S, A>>;
|
||||||
|
|
||||||
|
interface SplitUpdateStateRequestChunk {
|
||||||
|
readonly split: 'chunk';
|
||||||
|
readonly chunk: [string, string];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SplitUpdateStateRequestEnd {
|
||||||
|
readonly split: 'end';
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SplitUpdateStateRequest<S, A extends Action<string>> =
|
||||||
|
| SplitUpdateStateRequestStart<S, A>
|
||||||
|
| SplitUpdateStateRequestChunk
|
||||||
|
| SplitUpdateStateRequestEnd;
|
||||||
|
|
||||||
|
interface SplitUpdateStateAction<S, A extends Action<string>> {
|
||||||
|
readonly type: typeof UPDATE_STATE;
|
||||||
|
request: SplitUpdateStateRequest<S, A>;
|
||||||
|
readonly id: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
export type TabMessage =
|
export type TabMessage =
|
||||||
| StartAction
|
| StartAction
|
||||||
| StopAction
|
| StopAction
|
||||||
| OptionsMessage
|
| OptionsAction
|
||||||
| DispatchAction
|
| DispatchAction
|
||||||
| ImportAction
|
| ImportAction
|
||||||
| ActionAction
|
| ActionAction
|
||||||
| ExportAction;
|
| ExportAction;
|
||||||
export type PanelMessage<S, A extends Action<string>> =
|
export type PanelMessageWithoutNA<S, A extends Action<string>> =
|
||||||
| NAAction
|
|
||||||
| ErrorMessage
|
| ErrorMessage
|
||||||
| UpdateStateAction<S, A>
|
| UpdateStateAction<S, A>
|
||||||
| SetPersistAction;
|
| SetPersistAction;
|
||||||
export type MonitorMessage =
|
export type PanelMessage<S, A extends Action<string>> =
|
||||||
| NAAction
|
| PanelMessageWithoutNA<S, A>
|
||||||
| ErrorMessage
|
| NAAction;
|
||||||
| EmptyUpdateStateAction
|
export type PanelMessageWithSplitAction<S, A extends Action<string>> =
|
||||||
| SetPersistAction;
|
| PanelMessage<S, A>
|
||||||
|
| SplitUpdateStateAction<S, A>;
|
||||||
|
|
||||||
type TabPort = Omit<chrome.runtime.Port, 'postMessage'> & {
|
type TabPort = Omit<chrome.runtime.Port, 'postMessage'> & {
|
||||||
postMessage: (message: TabMessage) => void;
|
postMessage: (message: TabMessage) => void;
|
||||||
};
|
};
|
||||||
type PanelPort = Omit<chrome.runtime.Port, 'postMessage'> & {
|
type PanelPort = Omit<chrome.runtime.Port, 'postMessage'> & {
|
||||||
postMessage: <S, A extends Action<string>>(
|
postMessage: <S, A extends Action<string>>(
|
||||||
message: PanelMessage<S, A>,
|
message: PanelMessageWithSplitAction<S, A>,
|
||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
type MonitorPort = Omit<chrome.runtime.Port, 'postMessage'> & {
|
|
||||||
postMessage: (message: MonitorMessage) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CONNECTED = 'socket/CONNECTED';
|
export const CONNECTED = 'socket/CONNECTED';
|
||||||
export const DISCONNECTED = 'socket/DISCONNECTED';
|
export const DISCONNECTED = 'socket/DISCONNECTED';
|
||||||
const connections: {
|
const connections: {
|
||||||
readonly tab: { [K in number | string]: TabPort };
|
readonly tab: { [K in number | string]: TabPort };
|
||||||
readonly panel: { [K in number | string]: PanelPort };
|
readonly panel: { [K in number | string]: PanelPort };
|
||||||
readonly monitor: { [K in number | string]: MonitorPort };
|
|
||||||
} = {
|
} = {
|
||||||
tab: {},
|
tab: {},
|
||||||
panel: {},
|
panel: {},
|
||||||
monitor: {},
|
|
||||||
};
|
};
|
||||||
const chunks: {
|
const chunks: {
|
||||||
[instanceId: string]: PageScriptToContentScriptMessageForwardedToMonitors<
|
[instanceId: string]: PageScriptToContentScriptMessageForwardedToMonitors<
|
||||||
|
@ -218,7 +235,6 @@ const chunks: {
|
||||||
>;
|
>;
|
||||||
} = {};
|
} = {};
|
||||||
let monitors = 0;
|
let monitors = 0;
|
||||||
let isMonitored = false;
|
|
||||||
|
|
||||||
const getId = (sender: chrome.runtime.MessageSender, name?: string) =>
|
const getId = (sender: chrome.runtime.MessageSender, name?: string) =>
|
||||||
sender.tab ? sender.tab.id! : name || sender.id!;
|
sender.tab ? sender.tab.id! : name || sender.id!;
|
||||||
|
@ -229,21 +245,63 @@ type MonitorAction<S, A extends Action<string>> =
|
||||||
| UpdateStateAction<S, A>
|
| UpdateStateAction<S, A>
|
||||||
| SetPersistAction;
|
| SetPersistAction;
|
||||||
|
|
||||||
function toMonitors<S, A extends Action<string>>(
|
// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts
|
||||||
action: MonitorAction<S, A>,
|
const maxChromeMsgSize = 32 * 1024 * 1024;
|
||||||
tabId?: string | number,
|
|
||||||
verbose?: boolean,
|
function toMonitors<S, A extends Action<string>>(action: MonitorAction<S, A>) {
|
||||||
) {
|
for (const port of Object.values(connections.panel)) {
|
||||||
Object.keys(connections.monitor).forEach((id) => {
|
try {
|
||||||
connections.monitor[id].postMessage(
|
port.postMessage(action);
|
||||||
verbose || action.type === 'ERROR' || action.type === SET_PERSIST
|
} catch (err) {
|
||||||
? action
|
if (
|
||||||
: { type: UPDATE_STATE },
|
action.type !== UPDATE_STATE ||
|
||||||
);
|
err == null ||
|
||||||
});
|
(err as Error).message !==
|
||||||
Object.keys(connections.panel).forEach((id) => {
|
'Message length exceeded maximum allowed length.'
|
||||||
connections.panel[id].postMessage(action);
|
) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const splitMessageStart: SplitUpdateStateRequestStart<S, A> = {
|
||||||
|
split: 'start',
|
||||||
|
};
|
||||||
|
const toSplit: [string, string][] = [];
|
||||||
|
let size = 0;
|
||||||
|
for (const [key, value] of Object.entries(
|
||||||
|
action.request as unknown as Record<string, unknown>,
|
||||||
|
)) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
size += value.length;
|
||||||
|
if (size > maxChromeMsgSize) {
|
||||||
|
toSplit.push([key, value]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(splitMessageStart as any)[key as keyof typeof splitMessageStart] =
|
||||||
|
value;
|
||||||
|
}
|
||||||
|
|
||||||
|
port.postMessage({ ...action, request: splitMessageStart });
|
||||||
|
|
||||||
|
for (let i = 0; i < toSplit.length; i++) {
|
||||||
|
for (let j = 0; j < toSplit[i][1].length; j += maxChromeMsgSize) {
|
||||||
|
port.postMessage({
|
||||||
|
...action,
|
||||||
|
request: {
|
||||||
|
split: 'chunk',
|
||||||
|
chunk: [
|
||||||
|
toSplit[i][0],
|
||||||
|
toSplit[i][1].substring(j, j + maxChromeMsgSize),
|
||||||
|
],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
port.postMessage({ ...action, request: { split: 'end' } });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMessage {
|
interface ImportMessage {
|
||||||
|
@ -263,7 +321,7 @@ function toContentScript(messageBody: ToContentScriptMessage) {
|
||||||
type: message,
|
type: message,
|
||||||
action,
|
action,
|
||||||
state: nonReduxDispatch(
|
state: nonReduxDispatch(
|
||||||
window.store,
|
store,
|
||||||
message,
|
message,
|
||||||
instanceId,
|
instanceId,
|
||||||
action as AppDispatchAction,
|
action as AppDispatchAction,
|
||||||
|
@ -277,7 +335,7 @@ function toContentScript(messageBody: ToContentScriptMessage) {
|
||||||
type: message,
|
type: message,
|
||||||
action,
|
action,
|
||||||
state: nonReduxDispatch(
|
state: nonReduxDispatch(
|
||||||
window.store,
|
store,
|
||||||
message,
|
message,
|
||||||
instanceId,
|
instanceId,
|
||||||
action as unknown as AppDispatchAction,
|
action as unknown as AppDispatchAction,
|
||||||
|
@ -291,7 +349,7 @@ function toContentScript(messageBody: ToContentScriptMessage) {
|
||||||
type: message,
|
type: message,
|
||||||
action,
|
action,
|
||||||
state: nonReduxDispatch(
|
state: nonReduxDispatch(
|
||||||
window.store,
|
store,
|
||||||
message,
|
message,
|
||||||
instanceId,
|
instanceId,
|
||||||
action as unknown as AppDispatchAction,
|
action as unknown as AppDispatchAction,
|
||||||
|
@ -305,7 +363,7 @@ function toContentScript(messageBody: ToContentScriptMessage) {
|
||||||
type: message,
|
type: message,
|
||||||
action,
|
action,
|
||||||
state: nonReduxDispatch(
|
state: nonReduxDispatch(
|
||||||
window.store,
|
store,
|
||||||
message,
|
message,
|
||||||
instanceId,
|
instanceId,
|
||||||
action as unknown as AppDispatchAction,
|
action as unknown as AppDispatchAction,
|
||||||
|
@ -319,7 +377,7 @@ function toContentScript(messageBody: ToContentScriptMessage) {
|
||||||
type: message,
|
type: message,
|
||||||
action,
|
action,
|
||||||
state: nonReduxDispatch(
|
state: nonReduxDispatch(
|
||||||
window.store,
|
store,
|
||||||
message,
|
message,
|
||||||
instanceId,
|
instanceId,
|
||||||
action as AppDispatchAction,
|
action as AppDispatchAction,
|
||||||
|
@ -331,27 +389,13 @@ function toContentScript(messageBody: ToContentScriptMessage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function toAllTabs(msg: TabMessage) {
|
function toAllTabs(msg: TabMessage) {
|
||||||
const tabs = connections.tab;
|
for (const tabPort of Object.values(connections.tab)) {
|
||||||
Object.keys(tabs).forEach((id) => {
|
tabPort.postMessage(msg);
|
||||||
tabs[id].postMessage(msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function monitorInstances(shouldMonitor: boolean, id?: string) {
|
|
||||||
if (!id && isMonitored === shouldMonitor) return;
|
|
||||||
const action = {
|
|
||||||
type: shouldMonitor ? ('START' as const) : ('STOP' as const),
|
|
||||||
};
|
|
||||||
if (id) {
|
|
||||||
if (connections.tab[id]) connections.tab[id].postMessage(action);
|
|
||||||
} else {
|
|
||||||
toAllTabs(action);
|
|
||||||
}
|
}
|
||||||
isMonitored = shouldMonitor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReducerError() {
|
function getReducerError() {
|
||||||
const instancesState = window.store.getState().instances;
|
const instancesState = store.getState().instances;
|
||||||
const payload = instancesState.states[instancesState.current];
|
const payload = instancesState.states[instancesState.current];
|
||||||
const computedState = payload.computedStates[payload.currentStateIndex];
|
const computedState = payload.computedStates[payload.currentStateIndex];
|
||||||
if (!computedState) return false;
|
if (!computedState) return false;
|
||||||
|
@ -359,13 +403,13 @@ function getReducerError() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePersist() {
|
function togglePersist() {
|
||||||
const state = window.store.getState();
|
const state = store.getState();
|
||||||
if (state.instances.persisted) {
|
if (state.instances.persisted) {
|
||||||
Object.keys(state.instances.connections).forEach((id) => {
|
for (const id of Object.keys(state.instances.connections)) {
|
||||||
if (connections.tab[id]) return;
|
if (connections.tab[id]) return;
|
||||||
window.store.dispatch({ type: REMOVE_INSTANCE, id });
|
store.dispatch({ type: REMOVE_INSTANCE, id });
|
||||||
toMonitors({ type: 'NA', id });
|
toMonitors({ type: 'NA', id });
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,34 +422,25 @@ interface OpenOptionsMessage {
|
||||||
readonly type: 'OPEN_OPTIONS';
|
readonly type: 'OPEN_OPTIONS';
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetOptionsMessage {
|
export type SingleMessage = OpenMessage | OpenOptionsMessage | OptionsMessage;
|
||||||
readonly type: 'GET_OPTIONS';
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SingleMessage =
|
|
||||||
| OpenMessage
|
|
||||||
| OpenOptionsMessage
|
|
||||||
| GetOptionsMessage;
|
|
||||||
|
|
||||||
type BackgroundStoreMessage<S, A extends Action<string>> =
|
type BackgroundStoreMessage<S, A extends Action<string>> =
|
||||||
| PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<S, A>
|
| PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<S, A>
|
||||||
| SplitMessage
|
| SplitMessage
|
||||||
| SingleMessage;
|
| SingleMessage;
|
||||||
type BackgroundStoreResponse = { readonly options: Options };
|
|
||||||
|
|
||||||
// Receive messages from content scripts
|
// Receive messages from content scripts
|
||||||
function messaging<S, A extends Action<string>>(
|
function messaging<S, A extends Action<string>>(
|
||||||
request: BackgroundStoreMessage<S, A>,
|
request: BackgroundStoreMessage<S, A>,
|
||||||
sender: chrome.runtime.MessageSender,
|
sender: chrome.runtime.MessageSender,
|
||||||
sendResponse?: (response?: BackgroundStoreResponse) => void,
|
|
||||||
) {
|
) {
|
||||||
let tabId = getId(sender);
|
let tabId = getId(sender);
|
||||||
if (!tabId) return;
|
if (!tabId) return;
|
||||||
if (sender.frameId) tabId = `${tabId}-${sender.frameId}`;
|
if (sender.frameId) tabId = `${tabId}-${sender.frameId}`;
|
||||||
|
|
||||||
if (request.type === 'STOP') {
|
if (request.type === 'STOP') {
|
||||||
if (!Object.keys(window.store.getState().instances.connections).length) {
|
if (!Object.keys(store.getState().instances.connections).length) {
|
||||||
window.store.dispatch({ type: DISCONNECTED });
|
store.dispatch({ type: DISCONNECTED });
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -413,10 +448,8 @@ function messaging<S, A extends Action<string>>(
|
||||||
chrome.runtime.openOptionsPage();
|
chrome.runtime.openOptionsPage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (request.type === 'GET_OPTIONS') {
|
if (request.type === 'OPTIONS') {
|
||||||
window.syncOptions.get((options) => {
|
toAllTabs({ type: 'OPTIONS', options: request.options });
|
||||||
sendResponse!({ options });
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (request.type === 'GET_REPORT') {
|
if (request.type === 'GET_REPORT') {
|
||||||
|
@ -424,12 +457,8 @@ function messaging<S, A extends Action<string>>(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (request.type === 'OPEN') {
|
if (request.type === 'OPEN') {
|
||||||
let position: DevToolsPosition = 'devtools-left';
|
let position: DevToolsPosition = 'devtools-window';
|
||||||
if (
|
if (['remote', 'window'].includes(request.position)) {
|
||||||
['remote', 'panel', 'left', 'right', 'bottom'].indexOf(
|
|
||||||
request.position,
|
|
||||||
) !== -1
|
|
||||||
) {
|
|
||||||
position = ('devtools-' + request.position) as DevToolsPosition;
|
position = ('devtools-' + request.position) as DevToolsPosition;
|
||||||
}
|
}
|
||||||
openDevToolsWindow(position);
|
openDevToolsWindow(position);
|
||||||
|
@ -437,7 +466,7 @@ function messaging<S, A extends Action<string>>(
|
||||||
}
|
}
|
||||||
if (request.type === 'ERROR') {
|
if (request.type === 'ERROR') {
|
||||||
if (request.payload) {
|
if (request.payload) {
|
||||||
toMonitors(request, tabId);
|
toMonitors(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!request.message) return;
|
if (!request.message) return;
|
||||||
|
@ -477,19 +506,15 @@ function messaging<S, A extends Action<string>>(
|
||||||
if (request.instanceId) {
|
if (request.instanceId) {
|
||||||
action.request.instanceId = instanceId;
|
action.request.instanceId = instanceId;
|
||||||
}
|
}
|
||||||
window.store.dispatch(action);
|
store.dispatch(action);
|
||||||
|
|
||||||
if (request.type === 'EXPORT') {
|
toMonitors(action);
|
||||||
toMonitors(action, tabId, true);
|
|
||||||
} else {
|
|
||||||
toMonitors(action, tabId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function disconnect(
|
function disconnect(
|
||||||
type: 'tab' | 'monitor' | 'panel',
|
type: 'tab' | 'panel',
|
||||||
id: number | string,
|
id: number | string,
|
||||||
listener?: (message: any, port: chrome.runtime.Port) => void,
|
listener: (message: any, port: chrome.runtime.Port) => void,
|
||||||
) {
|
) {
|
||||||
return function disconnectListener() {
|
return function disconnectListener() {
|
||||||
const p = connections[type][id];
|
const p = connections[type][id];
|
||||||
|
@ -497,13 +522,13 @@ function disconnect(
|
||||||
if (p) p.onDisconnect.removeListener(disconnectListener);
|
if (p) p.onDisconnect.removeListener(disconnectListener);
|
||||||
delete connections[type][id];
|
delete connections[type][id];
|
||||||
if (type === 'tab') {
|
if (type === 'tab') {
|
||||||
if (!window.store.getState().instances.persisted) {
|
if (!store.getState().instances.persisted) {
|
||||||
window.store.dispatch({ type: REMOVE_INSTANCE, id });
|
store.dispatch({ type: REMOVE_INSTANCE, id });
|
||||||
toMonitors({ type: 'NA', id });
|
toMonitors({ type: 'NA', id });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
monitors--;
|
monitors--;
|
||||||
if (!monitors) monitorInstances(false);
|
if (monitors === 0) toAllTabs({ type: 'STOP' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -512,21 +537,22 @@ function onConnect<S, A extends Action<string>>(port: chrome.runtime.Port) {
|
||||||
let id: number | string;
|
let id: number | string;
|
||||||
let listener;
|
let listener;
|
||||||
|
|
||||||
window.store.dispatch({ type: CONNECTED, port });
|
store.dispatch({ type: CONNECTED, port });
|
||||||
|
|
||||||
if (port.name === 'tab') {
|
if (port.name === 'tab') {
|
||||||
id = getId(port.sender!);
|
id = getId(port.sender!);
|
||||||
if (port.sender!.frameId) id = `${id}-${port.sender!.frameId}`;
|
if (port.sender!.frameId) id = `${id}-${port.sender!.frameId}`;
|
||||||
connections.tab[id] = port;
|
connections.tab[id] = port;
|
||||||
listener = (msg: ContentScriptToBackgroundMessage<S, A>) => {
|
listener = (msg: ContentScriptToBackgroundMessage<S, A> | 'heartbeat') => {
|
||||||
|
if (msg === 'heartbeat') return;
|
||||||
if (msg.name === 'INIT_INSTANCE') {
|
if (msg.name === 'INIT_INSTANCE') {
|
||||||
if (typeof id === 'number') {
|
if (typeof id === 'number') {
|
||||||
chrome.pageAction.show(id);
|
chrome.action.enable(id);
|
||||||
chrome.pageAction.setIcon({ tabId: id, path: 'img/logo/38x38.png' });
|
chrome.action.setIcon({ tabId: id, path: 'img/logo/38x38.png' });
|
||||||
}
|
}
|
||||||
if (isMonitored) port.postMessage({ type: 'START' });
|
if (monitors > 0) port.postMessage({ type: 'START' });
|
||||||
|
|
||||||
const state = window.store.getState();
|
const state = store.getState();
|
||||||
if (state.instances.persisted) {
|
if (state.instances.persisted) {
|
||||||
const instanceId = `${id}/${msg.instanceId}`;
|
const instanceId = `${id}/${msg.instanceId}`;
|
||||||
const persistedState = state.instances.states[instanceId];
|
const persistedState = state.instances.states[instanceId];
|
||||||
|
@ -550,19 +576,14 @@ function onConnect<S, A extends Action<string>>(port: chrome.runtime.Port) {
|
||||||
port.onMessage.addListener(listener);
|
port.onMessage.addListener(listener);
|
||||||
port.onDisconnect.addListener(disconnect('tab', id, listener));
|
port.onDisconnect.addListener(disconnect('tab', id, listener));
|
||||||
} else if (port.name && port.name.indexOf('monitor') === 0) {
|
} else if (port.name && port.name.indexOf('monitor') === 0) {
|
||||||
id = getId(port.sender!, port.name);
|
|
||||||
connections.monitor[id] = port;
|
|
||||||
monitorInstances(true);
|
|
||||||
monitors++;
|
|
||||||
port.onDisconnect.addListener(disconnect('monitor', id));
|
|
||||||
} else {
|
|
||||||
// devpanel
|
// devpanel
|
||||||
id = port.name || port.sender!.frameId!;
|
id = getId(port.sender!, port.name);
|
||||||
connections.panel[id] = port;
|
connections.panel[id] = port;
|
||||||
monitorInstances(true, port.name);
|
|
||||||
monitors++;
|
monitors++;
|
||||||
listener = (msg: BackgroundAction) => {
|
toAllTabs({ type: 'START' });
|
||||||
window.store.dispatch(msg);
|
listener = (msg: BackgroundAction | 'heartbeat') => {
|
||||||
|
if (msg === 'heartbeat') return;
|
||||||
|
store.dispatch(msg);
|
||||||
};
|
};
|
||||||
port.onMessage.addListener(listener);
|
port.onMessage.addListener(listener);
|
||||||
port.onDisconnect.addListener(disconnect('panel', id, listener));
|
port.onDisconnect.addListener(disconnect('panel', id, listener));
|
||||||
|
@ -576,21 +597,13 @@ chrome.runtime.onMessageExternal.addListener(messaging);
|
||||||
|
|
||||||
chrome.notifications.onClicked.addListener((id) => {
|
chrome.notifications.onClicked.addListener((id) => {
|
||||||
chrome.notifications.clear(id);
|
chrome.notifications.clear(id);
|
||||||
openDevToolsWindow('devtools-right');
|
openDevToolsWindow('devtools-window');
|
||||||
});
|
});
|
||||||
|
|
||||||
declare global {
|
const api: Middleware<{}, BackgroundState, Dispatch<BackgroundAction>> =
|
||||||
interface Window {
|
(store) => (next) => (untypedAction) => {
|
||||||
syncOptions: SyncOptions;
|
const action = untypedAction as BackgroundAction;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.syncOptions = syncOptions(toAllTabs); // Expose to the options page
|
|
||||||
|
|
||||||
export default function api(
|
|
||||||
store: MiddlewareAPI<Dispatch<BackgroundAction>, BackgroundState>,
|
|
||||||
) {
|
|
||||||
return (next: Dispatch<BackgroundAction>) => (action: BackgroundAction) => {
|
|
||||||
if (action.type === LIFTED_ACTION) toContentScript(action);
|
if (action.type === LIFTED_ACTION) toContentScript(action);
|
||||||
else if (action.type === TOGGLE_PERSIST) {
|
else if (action.type === TOGGLE_PERSIST) {
|
||||||
togglePersist();
|
togglePersist();
|
||||||
|
@ -601,4 +614,5 @@ export default function api(
|
||||||
}
|
}
|
||||||
return next(action);
|
return next(action);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
export default api;
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import { combineReducers, Reducer } from 'redux';
|
import { combineReducers, Reducer } from 'redux';
|
||||||
import { instances, InstancesState } from '@redux-devtools/app';
|
import { instances, InstancesState } from '@redux-devtools/app';
|
||||||
import type { BackgroundAction } from './backgroundStore';
|
import { BackgroundAction } from './backgroundStore';
|
||||||
|
|
||||||
export interface BackgroundState {
|
export interface BackgroundState {
|
||||||
readonly instances: InstancesState;
|
readonly instances: InstancesState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootReducer: Reducer<BackgroundState, BackgroundAction> =
|
const rootReducer: Reducer<
|
||||||
combineReducers<BackgroundState>({
|
BackgroundState,
|
||||||
|
BackgroundAction,
|
||||||
|
Partial<BackgroundState>
|
||||||
|
> = combineReducers({
|
||||||
instances,
|
instances,
|
||||||
});
|
}) as any;
|
||||||
|
|
||||||
export default rootReducer;
|
export default rootReducer;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createStore, applyMiddleware, PreloadedState } from 'redux';
|
import { createStore, applyMiddleware } from 'redux';
|
||||||
import {
|
import {
|
||||||
CustomAction,
|
CustomAction,
|
||||||
DispatchAction,
|
DispatchAction,
|
||||||
|
@ -60,7 +60,7 @@ export type BackgroundAction =
|
||||||
| DisconnectedAction;
|
| DisconnectedAction;
|
||||||
|
|
||||||
export default function configureStore(
|
export default function configureStore(
|
||||||
preloadedState?: PreloadedState<BackgroundState>,
|
preloadedState?: Partial<BackgroundState>,
|
||||||
) {
|
) {
|
||||||
return createStore(rootReducer, preloadedState, applyMiddleware(api));
|
return createStore(rootReducer, preloadedState, applyMiddleware(api));
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
// Mock not supported chrome.* API for Firefox and Electron
|
// Mock not supported chrome.* API for Firefox and Electron
|
||||||
|
|
||||||
window.isElectron =
|
const isElectron = navigator.userAgent.includes('Electron');
|
||||||
window.navigator && window.navigator.userAgent.indexOf('Electron') !== -1;
|
const isFirefox = navigator.userAgent.includes('Firefox');
|
||||||
|
|
||||||
const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1;
|
|
||||||
|
|
||||||
// Background page only
|
// Background page only
|
||||||
if (
|
if (
|
||||||
(window.isElectron &&
|
(isElectron && location.pathname === '/background.bundle.js') ||
|
||||||
location.pathname === '/_generated_background_page.html') ||
|
|
||||||
isFirefox
|
isFirefox
|
||||||
) {
|
) {
|
||||||
(chrome.runtime as any).onConnectExternal = {
|
(chrome.runtime as any).onConnectExternal = {
|
||||||
|
@ -18,7 +15,7 @@ if (
|
||||||
addListener() {},
|
addListener() {},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (window.isElectron) {
|
if (isElectron) {
|
||||||
(chrome.notifications as any) = {
|
(chrome.notifications as any) = {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
addListener() {},
|
addListener() {},
|
||||||
|
@ -31,6 +28,11 @@ if (
|
||||||
addListener() {},
|
addListener() {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
(chrome.commands as any) = {
|
||||||
|
onCommand: {
|
||||||
|
addListener() {},
|
||||||
|
},
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
(chrome.storage as any).sync = chrome.storage.local;
|
(chrome.storage as any).sync = chrome.storage.local;
|
||||||
(chrome.runtime as any).onInstalled = {
|
(chrome.runtime as any).onInstalled = {
|
||||||
|
@ -39,7 +41,7 @@ if (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.isElectron) {
|
if (isElectron) {
|
||||||
if (!chrome.storage.local || !chrome.storage.local.remove) {
|
if (!chrome.storage.local || !chrome.storage.local.remove) {
|
||||||
(chrome.storage as any).local = {
|
(chrome.storage as any).local = {
|
||||||
set(obj: any, callback: any) {
|
set(obj: any, callback: any) {
|
||||||
|
@ -87,6 +89,6 @@ if (window.isElectron) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFirefox || window.isElectron) {
|
if (isFirefox || isElectron) {
|
||||||
(chrome.storage as any).sync = chrome.storage.local;
|
(chrome.storage as any).sync = chrome.storage.local;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import '../chromeApiMock';
|
import '../chromeApiMock';
|
||||||
import {
|
import {
|
||||||
injectOptions,
|
getOptions,
|
||||||
getOptionsFromBg,
|
|
||||||
isAllowed,
|
isAllowed,
|
||||||
|
Options,
|
||||||
|
prefetchOptions,
|
||||||
|
prepareOptionsForPage,
|
||||||
} from '../options/syncOptions';
|
} from '../options/syncOptions';
|
||||||
import type { TabMessage } from '../background/store/apiMiddleware';
|
import type { TabMessage } from '../background/store/apiMiddleware';
|
||||||
import type {
|
import type {
|
||||||
|
@ -16,6 +18,7 @@ import {
|
||||||
DispatchAction as AppDispatchAction,
|
DispatchAction as AppDispatchAction,
|
||||||
} from '@redux-devtools/app';
|
} from '@redux-devtools/app';
|
||||||
import { LiftedState } from '@redux-devtools/instrument';
|
import { LiftedState } from '@redux-devtools/instrument';
|
||||||
|
|
||||||
const source = '@devtools-extension';
|
const source = '@devtools-extension';
|
||||||
const pageSource = '@devtools-page';
|
const pageSource = '@devtools-page';
|
||||||
// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts
|
// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts
|
||||||
|
@ -83,6 +86,13 @@ interface UpdateAction {
|
||||||
readonly source: typeof source;
|
readonly source: typeof source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface OptionsAction {
|
||||||
|
readonly type: 'OPTIONS';
|
||||||
|
readonly options: Options;
|
||||||
|
readonly id: undefined;
|
||||||
|
readonly source: typeof source;
|
||||||
|
}
|
||||||
|
|
||||||
export type ContentScriptToPageScriptMessage =
|
export type ContentScriptToPageScriptMessage =
|
||||||
| StartAction
|
| StartAction
|
||||||
| StopAction
|
| StopAction
|
||||||
|
@ -90,7 +100,8 @@ export type ContentScriptToPageScriptMessage =
|
||||||
| ImportAction
|
| ImportAction
|
||||||
| ActionAction
|
| ActionAction
|
||||||
| ExportAction
|
| ExportAction
|
||||||
| UpdateAction;
|
| UpdateAction
|
||||||
|
| OptionsAction;
|
||||||
|
|
||||||
interface ImportStatePayload<S, A extends Action<string>> {
|
interface ImportStatePayload<S, A extends Action<string>> {
|
||||||
readonly type: 'IMPORT_STATE';
|
readonly type: 'IMPORT_STATE';
|
||||||
|
@ -111,6 +122,7 @@ export type ListenerMessage<S, A extends Action<string>> =
|
||||||
| ActionAction
|
| ActionAction
|
||||||
| ExportAction
|
| ExportAction
|
||||||
| UpdateAction
|
| UpdateAction
|
||||||
|
| OptionsAction
|
||||||
| ImportStateDispatchAction<S, A>;
|
| ImportStateDispatchAction<S, A>;
|
||||||
|
|
||||||
function postToPageScript(message: ContentScriptToPageScriptMessage) {
|
function postToPageScript(message: ContentScriptToPageScriptMessage) {
|
||||||
|
@ -155,8 +167,13 @@ function connect() {
|
||||||
source,
|
source,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if ('options' in message) {
|
} else if (message.type === 'OPTIONS') {
|
||||||
injectOptions(message.options);
|
postToPageScript({
|
||||||
|
type: message.type,
|
||||||
|
options: prepareOptionsForPage(message.options),
|
||||||
|
id: undefined,
|
||||||
|
source,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
postToPageScript({
|
postToPageScript({
|
||||||
type: message.type,
|
type: message.type,
|
||||||
|
@ -288,7 +305,14 @@ function send<S, A extends Action<string>>(
|
||||||
) {
|
) {
|
||||||
if (!connected) connect();
|
if (!connected) connect();
|
||||||
if (message.type === 'INIT_INSTANCE') {
|
if (message.type === 'INIT_INSTANCE') {
|
||||||
getOptionsFromBg();
|
getOptions((options) => {
|
||||||
|
postToPageScript({
|
||||||
|
type: 'OPTIONS',
|
||||||
|
options: prepareOptionsForPage(options),
|
||||||
|
id: undefined,
|
||||||
|
source,
|
||||||
|
});
|
||||||
|
});
|
||||||
postToBackground({ name: 'INIT_INSTANCE', instanceId: message.instanceId });
|
postToBackground({ name: 'INIT_INSTANCE', instanceId: message.instanceId });
|
||||||
} else {
|
} else {
|
||||||
postToBackground({ name: 'RELAY', message });
|
postToBackground({ name: 'RELAY', message });
|
||||||
|
@ -316,4 +340,10 @@ function handleMessages<S, A extends Action<string>>(
|
||||||
tryCatch(send, message);
|
tryCatch(send, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prefetchOptions();
|
||||||
|
|
||||||
window.addEventListener('message', handleMessages, false);
|
window.addEventListener('message', handleMessages, false);
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
bg?.postMessage('heartbeat');
|
||||||
|
}, 15000);
|
||||||
|
|
|
@ -5,12 +5,13 @@ html
|
||||||
meta(charset='UTF-8')
|
meta(charset='UTF-8')
|
||||||
title Redux DevTools
|
title Redux DevTools
|
||||||
include ../style.pug
|
include ../style.pug
|
||||||
style.
|
|
||||||
body {
|
|
||||||
min-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body
|
body
|
||||||
#root
|
#root
|
||||||
|
div(style='display: flex; justify-content: center; align-items: center')
|
||||||
|
img(
|
||||||
|
src='/img/loading.svg',
|
||||||
|
height=300, width=350,
|
||||||
|
)
|
||||||
link(href='/devpanel.bundle.css', rel='stylesheet')
|
link(href='/devpanel.bundle.css', rel='stylesheet')
|
||||||
script(src='/devpanel.bundle.js')
|
script(src='/devpanel.bundle.js')
|
||||||
|
|
|
@ -3,25 +3,35 @@ import React, { CSSProperties, ReactNode } from 'react';
|
||||||
import { createRoot, Root } from 'react-dom/client';
|
import { createRoot, Root } from 'react-dom/client';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { Persistor } from 'redux-persist';
|
import { Persistor } from 'redux-persist';
|
||||||
import { REMOVE_INSTANCE, StoreAction } from '@redux-devtools/app';
|
import {
|
||||||
|
REMOVE_INSTANCE,
|
||||||
|
StoreAction,
|
||||||
|
StoreState,
|
||||||
|
UPDATE_STATE,
|
||||||
|
} from '@redux-devtools/app';
|
||||||
import App from '../app/App';
|
import App from '../app/App';
|
||||||
import configureStore from './store/panelStore';
|
import configureStore from './store/panelStore';
|
||||||
|
|
||||||
import { Action, Store } from 'redux';
|
import { Action, Store } from 'redux';
|
||||||
import type { PanelMessage } from '../background/store/apiMiddleware';
|
import {
|
||||||
import type { StoreStateWithoutSocket } from './store/panelReducer';
|
PanelMessageWithoutNA,
|
||||||
|
PanelMessageWithSplitAction,
|
||||||
|
SplitUpdateStateRequest,
|
||||||
|
UpdateStateRequest,
|
||||||
|
} from '../background/store/apiMiddleware';
|
||||||
import { PersistGate } from 'redux-persist/integration/react';
|
import { PersistGate } from 'redux-persist/integration/react';
|
||||||
|
|
||||||
const position = location.hash;
|
const position = location.hash;
|
||||||
const messageStyle: CSSProperties = {
|
const messageStyle: CSSProperties = {
|
||||||
padding: '20px',
|
paddingTop: '20px',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
boxSizing: 'border-box',
|
||||||
};
|
};
|
||||||
|
|
||||||
let rendered: boolean | undefined;
|
let rendered: boolean | undefined;
|
||||||
let currentRoot: Root | undefined;
|
let currentRoot: Root | undefined;
|
||||||
let store: Store<StoreStateWithoutSocket, StoreAction> | undefined;
|
let store: Store<StoreState, StoreAction> | undefined;
|
||||||
let persistor: Persistor | undefined;
|
let persistor: Persistor | undefined;
|
||||||
let bgConnection: chrome.runtime.Port;
|
let bgConnection: chrome.runtime.Port;
|
||||||
let naTimeout: NodeJS.Timeout;
|
let naTimeout: NodeJS.Timeout;
|
||||||
|
@ -63,7 +73,12 @@ function renderNA() {
|
||||||
.
|
.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
if (isChrome) {
|
if (
|
||||||
|
isChrome &&
|
||||||
|
chrome &&
|
||||||
|
chrome.devtools &&
|
||||||
|
chrome.devtools.inspectedWindow
|
||||||
|
) {
|
||||||
chrome.devtools.inspectedWindow.getResources((resources) => {
|
chrome.devtools.inspectedWindow.getResources((resources) => {
|
||||||
if (resources[0].url.substr(0, 4) === 'file') {
|
if (resources[0].url.substr(0, 4) === 'file') {
|
||||||
message = (
|
message = (
|
||||||
|
@ -90,22 +105,74 @@ function renderNA() {
|
||||||
}, 3500);
|
}, 3500);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(id: number) {
|
let splitMessage: SplitUpdateStateRequest<unknown, Action<string>>;
|
||||||
|
|
||||||
|
function init() {
|
||||||
renderNA();
|
renderNA();
|
||||||
bgConnection = chrome.runtime.connect({
|
|
||||||
name: id ? id.toString() : undefined,
|
let name = 'monitor';
|
||||||
});
|
if (chrome && chrome.devtools && chrome.devtools.inspectedWindow) {
|
||||||
|
name += chrome.devtools.inspectedWindow.tabId;
|
||||||
|
}
|
||||||
|
bgConnection = chrome.runtime.connect({ name });
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
bgConnection.postMessage('heartbeat');
|
||||||
|
}, 15000);
|
||||||
|
|
||||||
bgConnection.onMessage.addListener(
|
bgConnection.onMessage.addListener(
|
||||||
<S, A extends Action<string>>(message: PanelMessage<S, A>) => {
|
<S, A extends Action<string>>(
|
||||||
|
message: PanelMessageWithSplitAction<S, A>,
|
||||||
|
) => {
|
||||||
if (message.type === 'NA') {
|
if (message.type === 'NA') {
|
||||||
if (message.id === id) renderNA();
|
// TODO Double-check this now that the name is different
|
||||||
|
if (message.id === name) renderNA();
|
||||||
else store!.dispatch({ type: REMOVE_INSTANCE, id: message.id });
|
else store!.dispatch({ type: REMOVE_INSTANCE, id: message.id });
|
||||||
} else {
|
} else {
|
||||||
if (!rendered) renderDevTools();
|
if (!rendered) renderDevTools();
|
||||||
store!.dispatch(message);
|
|
||||||
|
if (
|
||||||
|
message.type === UPDATE_STATE &&
|
||||||
|
(message.request as SplitUpdateStateRequest<S, A>).split
|
||||||
|
) {
|
||||||
|
const request = message.request as SplitUpdateStateRequest<S, A>;
|
||||||
|
|
||||||
|
if (request.split === 'start') {
|
||||||
|
splitMessage = request;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.split === 'chunk') {
|
||||||
|
if ((splitMessage as Record<string, unknown>)[request.chunk[0]]) {
|
||||||
|
(splitMessage as Record<string, unknown>)[request.chunk[0]] +=
|
||||||
|
request.chunk[1];
|
||||||
|
} else {
|
||||||
|
(splitMessage as Record<string, unknown>)[request.chunk[0]] =
|
||||||
|
request.chunk[1];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.split === 'end') {
|
||||||
|
store!.dispatch({
|
||||||
|
...message,
|
||||||
|
request: splitMessage as UpdateStateRequest<S, A>,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Unable to process split message with type: ${(request as any).split}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
store!.dispatch(message as PanelMessageWithoutNA<S, A>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
init(chrome.devtools.inspectedWindow.tabId);
|
if (position === '#popup') document.body.style.minWidth = '760px';
|
||||||
|
if (position !== '#popup') document.body.style.minHeight = '100%';
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
|
@ -1,45 +1,32 @@
|
||||||
import { combineReducers, Reducer } from 'redux';
|
import { combineReducers, Reducer } from 'redux';
|
||||||
import {
|
import {
|
||||||
connection,
|
connection,
|
||||||
ConnectionState,
|
|
||||||
instances,
|
instances,
|
||||||
InstancesState,
|
|
||||||
monitor,
|
monitor,
|
||||||
MonitorState,
|
|
||||||
notification,
|
notification,
|
||||||
NotificationState,
|
|
||||||
reports,
|
reports,
|
||||||
ReportsState,
|
|
||||||
section,
|
section,
|
||||||
SectionState,
|
socket,
|
||||||
StateTreeSettings,
|
|
||||||
stateTreeSettings,
|
stateTreeSettings,
|
||||||
StoreAction,
|
StoreAction,
|
||||||
|
StoreState,
|
||||||
theme,
|
theme,
|
||||||
ThemeState,
|
|
||||||
} from '@redux-devtools/app';
|
} from '@redux-devtools/app';
|
||||||
|
|
||||||
export interface StoreStateWithoutSocket {
|
const rootReducer: Reducer<
|
||||||
readonly section: SectionState;
|
StoreState,
|
||||||
readonly theme: ThemeState;
|
StoreAction,
|
||||||
readonly connection: ConnectionState;
|
Partial<StoreState>
|
||||||
readonly monitor: MonitorState;
|
> = combineReducers({
|
||||||
readonly instances: InstancesState;
|
|
||||||
readonly reports: ReportsState;
|
|
||||||
readonly notification: NotificationState;
|
|
||||||
readonly stateTreeSettings: StateTreeSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rootReducer: Reducer<StoreStateWithoutSocket, StoreAction> =
|
|
||||||
combineReducers<StoreStateWithoutSocket>({
|
|
||||||
instances,
|
instances,
|
||||||
monitor,
|
monitor,
|
||||||
reports,
|
reports,
|
||||||
notification,
|
notification,
|
||||||
section,
|
section,
|
||||||
|
socket,
|
||||||
theme,
|
theme,
|
||||||
connection,
|
connection,
|
||||||
stateTreeSettings,
|
stateTreeSettings,
|
||||||
});
|
}) as any;
|
||||||
|
|
||||||
export default rootReducer;
|
export default rootReducer;
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
import { createStore, applyMiddleware, Reducer } from 'redux';
|
import { createStore, applyMiddleware, Reducer, Store } from 'redux';
|
||||||
import localForage from 'localforage';
|
import localForage from 'localforage';
|
||||||
import { persistReducer, persistStore } from 'redux-persist';
|
import { persistReducer, persistStore } from 'redux-persist';
|
||||||
import { exportStateMiddleware, StoreAction } from '@redux-devtools/app';
|
import {
|
||||||
|
exportStateMiddleware,
|
||||||
|
StoreAction,
|
||||||
|
StoreState,
|
||||||
|
} from '@redux-devtools/app';
|
||||||
import panelDispatcher from './panelSyncMiddleware';
|
import panelDispatcher from './panelSyncMiddleware';
|
||||||
import rootReducer, { StoreStateWithoutSocket } from './panelReducer';
|
import rootReducer from './panelReducer';
|
||||||
|
|
||||||
const persistConfig = {
|
const persistConfig = {
|
||||||
key: 'redux-devtools',
|
key: 'redux-devtools',
|
||||||
|
@ -11,8 +15,10 @@ const persistConfig = {
|
||||||
storage: localForage,
|
storage: localForage,
|
||||||
};
|
};
|
||||||
|
|
||||||
const persistedReducer: Reducer<StoreStateWithoutSocket, StoreAction> =
|
const persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(
|
||||||
persistReducer(persistConfig, rootReducer) as any;
|
persistConfig,
|
||||||
|
rootReducer,
|
||||||
|
) as any;
|
||||||
|
|
||||||
export default function configureStore(
|
export default function configureStore(
|
||||||
position: string,
|
position: string,
|
||||||
|
@ -23,6 +29,6 @@ export default function configureStore(
|
||||||
panelDispatcher(bgConnection),
|
panelDispatcher(bgConnection),
|
||||||
);
|
);
|
||||||
const store = createStore(persistedReducer, enhancer);
|
const store = createStore(persistedReducer, enhancer);
|
||||||
const persistor = persistStore(store);
|
const persistor = persistStore(store as Store);
|
||||||
return { store, persistor };
|
return { store, persistor };
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,52 @@ import {
|
||||||
TOGGLE_PERSIST,
|
TOGGLE_PERSIST,
|
||||||
UPDATE_STATE,
|
UPDATE_STATE,
|
||||||
} from '@redux-devtools/app';
|
} from '@redux-devtools/app';
|
||||||
import { Dispatch, MiddlewareAPI } from 'redux';
|
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
|
||||||
|
|
||||||
function panelDispatcher(bgConnection: chrome.runtime.Port) {
|
function selectInstance(
|
||||||
let autoselected = false;
|
tabId: number,
|
||||||
const tabId = chrome.devtools.inspectedWindow.tabId;
|
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
|
||||||
|
next: (action: unknown) => unknown,
|
||||||
return (store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) =>
|
) {
|
||||||
(next: Dispatch<StoreAction>) =>
|
const instances = store.getState().instances;
|
||||||
(action: StoreAction) => {
|
if (instances.current === 'default') return;
|
||||||
const result = next(action);
|
const connections = instances.connections[tabId];
|
||||||
if (!autoselected && action.type === UPDATE_STATE && tabId) {
|
|
||||||
autoselected = true;
|
|
||||||
const connections = store.getState().instances.connections[tabId];
|
|
||||||
if (connections && connections.length === 1) {
|
if (connections && connections.length === 1) {
|
||||||
next({ type: SELECT_INSTANCE, selected: connections[0] });
|
next({ type: SELECT_INSTANCE, selected: connections[0] });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentTabId(next: (tabId: number) => void) {
|
||||||
|
chrome.tabs.query(
|
||||||
|
{
|
||||||
|
active: true,
|
||||||
|
lastFocusedWindow: true,
|
||||||
|
},
|
||||||
|
(tabs) => {
|
||||||
|
const tab = tabs[0];
|
||||||
|
if (!tab) return;
|
||||||
|
next(tab.id!);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function panelDispatcher(
|
||||||
|
bgConnection: chrome.runtime.Port,
|
||||||
|
): Middleware<{}, StoreState, Dispatch<StoreAction>> {
|
||||||
|
let autoselected = false;
|
||||||
|
|
||||||
|
return (store) => (next) => (untypedAction) => {
|
||||||
|
const action = untypedAction as StoreAction;
|
||||||
|
|
||||||
|
const result = next(action);
|
||||||
|
if (!autoselected && action.type === UPDATE_STATE) {
|
||||||
|
autoselected = true;
|
||||||
|
|
||||||
|
if (chrome.devtools && chrome.devtools.inspectedWindow) {
|
||||||
|
selectInstance(chrome.devtools.inspectedWindow.tabId, store, next);
|
||||||
|
} else {
|
||||||
|
getCurrentTabId((tabId) => selectInstance(tabId, store, next));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) {
|
if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) {
|
||||||
const instances = store.getState().instances;
|
const instances = store.getState().instances;
|
||||||
|
|
|
@ -1,17 +1,6 @@
|
||||||
function createPanel(url: string) {
|
chrome.devtools.panels.create(
|
||||||
chrome.devtools.panels.create(
|
|
||||||
'Redux',
|
'Redux',
|
||||||
'img/logo/scalable.png',
|
'img/logo/scalable.png',
|
||||||
url,
|
'devpanel.html',
|
||||||
function () {},
|
() => {},
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
if (chrome.runtime.getBackgroundPage) {
|
|
||||||
// Check if the background page's object is accessible (not in incognito)
|
|
||||||
chrome.runtime.getBackgroundPage((background) => {
|
|
||||||
createPanel(background ? 'window.html' : 'devpanel.html');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
createPanel('devpanel.html');
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,22 +2,25 @@ import '../chromeApiMock';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import OptionsComponent from './Options';
|
import OptionsComponent from './Options';
|
||||||
import { Options } from './syncOptions';
|
import {
|
||||||
|
getOptions,
|
||||||
|
Options,
|
||||||
|
OptionsMessage,
|
||||||
|
saveOption,
|
||||||
|
subscribeToOptions,
|
||||||
|
} from './syncOptions';
|
||||||
|
|
||||||
chrome.runtime.getBackgroundPage((background) => {
|
subscribeToOptions((options) => {
|
||||||
const syncOptions = background!.syncOptions;
|
const message: OptionsMessage = { type: 'OPTIONS', options };
|
||||||
|
chrome.runtime.sendMessage(message);
|
||||||
|
});
|
||||||
|
|
||||||
const saveOption = <K extends keyof Options>(name: K, value: Options[K]) => {
|
const renderOptions = (options: Options) => {
|
||||||
syncOptions.save(name, value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderOptions = (options: Options) => {
|
|
||||||
const root = createRoot(document.getElementById('root')!);
|
const root = createRoot(document.getElementById('root')!);
|
||||||
root.render(<OptionsComponent options={options} saveOption={saveOption} />);
|
root.render(<OptionsComponent options={options} saveOption={saveOption} />);
|
||||||
};
|
};
|
||||||
|
|
||||||
syncOptions.subscribe(renderOptions);
|
subscribeToOptions(renderOptions);
|
||||||
syncOptions.get((options) => {
|
getOptions((options) => {
|
||||||
renderOptions(options);
|
renderOptions(options);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,21 +38,22 @@ let options: Options | undefined;
|
||||||
let subscribers: ((options: Options) => void)[] = [];
|
let subscribers: ((options: Options) => void)[] = [];
|
||||||
|
|
||||||
export interface OptionsMessage {
|
export interface OptionsMessage {
|
||||||
|
readonly type: 'OPTIONS';
|
||||||
readonly options: Options;
|
readonly options: Options;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToAllTabs = (msg: OptionsMessage) => void;
|
export const saveOption = <K extends keyof Options>(
|
||||||
|
key: K,
|
||||||
const save =
|
value: Options[K],
|
||||||
(toAllTabs: ToAllTabs | undefined) =>
|
) => {
|
||||||
<K extends keyof Options>(key: K, value: Options[K]) => {
|
|
||||||
let obj: { [K1 in keyof Options]?: Options[K1] } = {};
|
let obj: { [K1 in keyof Options]?: Options[K1] } = {};
|
||||||
obj[key] = value;
|
obj[key] = value;
|
||||||
chrome.storage.sync.set(obj);
|
chrome.storage.sync.set(obj);
|
||||||
options![key] = value;
|
options![key] = value;
|
||||||
toAllTabs!({ options: options! });
|
for (const subscriber of subscribers) {
|
||||||
subscribers.forEach((s) => s(options!));
|
subscriber(options!);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const migrateOldOptions = (oldOptions: OldOrNewOptions): Options => ({
|
const migrateOldOptions = (oldOptions: OldOrNewOptions): Options => ({
|
||||||
...oldOptions,
|
...oldOptions,
|
||||||
|
@ -71,7 +72,7 @@ const migrateOldOptions = (oldOptions: OldOrNewOptions): Options => ({
|
||||||
: oldOptions.filter,
|
: oldOptions.filter,
|
||||||
});
|
});
|
||||||
|
|
||||||
const get = (callback: (options: Options) => void) => {
|
export const getOptions = (callback: (options: Options) => void) => {
|
||||||
if (options) callback(options);
|
if (options) callback(options);
|
||||||
else {
|
else {
|
||||||
chrome.storage.sync.get(
|
chrome.storage.sync.get(
|
||||||
|
@ -98,67 +99,29 @@ const get = (callback: (options: Options) => void) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const subscribe = (callback: (options: Options) => void) => {
|
export const prefetchOptions = () => getOptions(() => {});
|
||||||
|
|
||||||
|
export const subscribeToOptions = (callback: (options: Options) => void) => {
|
||||||
subscribers = subscribers.concat(callback);
|
subscribers = subscribers.concat(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toReg = (str: string) =>
|
const toReg = (str: string) =>
|
||||||
str !== '' ? str.split('\n').filter(Boolean).join('|') : null;
|
str !== '' ? str.split('\n').filter(Boolean).join('|') : null;
|
||||||
|
|
||||||
export const injectOptions = (newOptions: Options) => {
|
export const prepareOptionsForPage = (options: Options): Options => ({
|
||||||
if (!newOptions) return;
|
...options,
|
||||||
|
|
||||||
options = {
|
|
||||||
...newOptions,
|
|
||||||
allowlist:
|
allowlist:
|
||||||
newOptions.filter !== FilterState.DO_NOT_FILTER
|
options.filter !== FilterState.DO_NOT_FILTER
|
||||||
? toReg(newOptions.allowlist)!
|
? toReg(options.allowlist)!
|
||||||
: newOptions.allowlist,
|
: options.allowlist,
|
||||||
denylist:
|
denylist:
|
||||||
newOptions.filter !== FilterState.DO_NOT_FILTER
|
options.filter !== FilterState.DO_NOT_FILTER
|
||||||
? toReg(newOptions.denylist)!
|
? toReg(options.denylist)!
|
||||||
: newOptions.denylist,
|
: options.denylist,
|
||||||
};
|
});
|
||||||
let s = document.createElement('script');
|
|
||||||
s.type = 'text/javascript';
|
|
||||||
s.appendChild(
|
|
||||||
document.createTextNode(
|
|
||||||
'window.devToolsOptions = Object.assign(window.devToolsOptions||{},' +
|
|
||||||
JSON.stringify(options) +
|
|
||||||
');',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
(document.head || document.documentElement).appendChild(s);
|
|
||||||
s.parentNode!.removeChild(s);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getOptionsFromBg = () => {
|
|
||||||
/* chrome.runtime.sendMessage({ type: 'GET_OPTIONS' }, response => {
|
|
||||||
if (response && response.options) injectOptions(response.options);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
get((newOptions) => {
|
|
||||||
injectOptions(newOptions);
|
|
||||||
}); // Legacy
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isAllowed = (localOptions = options) =>
|
export const isAllowed = (localOptions = options) =>
|
||||||
!localOptions ||
|
!localOptions ||
|
||||||
localOptions.inject ||
|
localOptions.inject ||
|
||||||
!localOptions.urls ||
|
!localOptions.urls ||
|
||||||
location.href.match(toReg(localOptions.urls)!);
|
location.href.match(toReg(localOptions.urls)!);
|
||||||
|
|
||||||
export interface SyncOptions {
|
|
||||||
readonly save: <K extends keyof Options>(key: K, value: Options[K]) => void;
|
|
||||||
readonly get: (callback: (options: Options) => void) => void;
|
|
||||||
readonly subscribe: (callback: (options: Options) => void) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function syncOptions(toAllTabs?: ToAllTabs): SyncOptions {
|
|
||||||
if (toAllTabs && !options) get(() => {}); // Initialize
|
|
||||||
return {
|
|
||||||
save: save(toAllTabs),
|
|
||||||
get: get,
|
|
||||||
subscribe: subscribe,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import mapValues from 'lodash/mapValues';
|
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
import { LiftedState, PerformAction } from '@redux-devtools/instrument';
|
import { LiftedState, PerformAction } from '@redux-devtools/instrument';
|
||||||
import { LocalFilter } from '@redux-devtools/utils';
|
import { LocalFilter } from '@redux-devtools/utils';
|
||||||
|
@ -46,10 +45,15 @@ function filterActions<A extends Action<string>>(
|
||||||
actionSanitizer: ((action: A, id: number) => A) | undefined,
|
actionSanitizer: ((action: A, id: number) => A) | undefined,
|
||||||
): { [p: number]: PerformAction<A> } {
|
): { [p: number]: PerformAction<A> } {
|
||||||
if (!actionSanitizer) return actionsById;
|
if (!actionSanitizer) return actionsById;
|
||||||
return mapValues(actionsById, (action, id) => ({
|
return Object.fromEntries(
|
||||||
|
Object.entries(actionsById).map(([actionId, action]) => [
|
||||||
|
actionId,
|
||||||
|
{
|
||||||
...action,
|
...action,
|
||||||
action: actionSanitizer(action.action, id as unknown as number),
|
action: actionSanitizer(action.action, actionId as unknown as number),
|
||||||
}));
|
},
|
||||||
|
]),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterStates<S>(
|
function filterStates<S>(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import jsan, { Options } from 'jsan';
|
import jsan, { Options } from 'jsan';
|
||||||
import throttle from 'lodash/throttle';
|
import { throttle } from 'lodash-es';
|
||||||
import { immutableSerialize } from '@redux-devtools/serialize';
|
import { immutableSerialize } from '@redux-devtools/serialize';
|
||||||
import { getActionsArray, getLocalFilter } from '@redux-devtools/utils';
|
import { getActionsArray, getLocalFilter } from '@redux-devtools/utils';
|
||||||
import { isFiltered, PartialLiftedState } from './filters';
|
import { isFiltered, PartialLiftedState } from './filters';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Action } from 'redux';
|
import { Action } from 'redux';
|
||||||
import type { PageScriptToContentScriptMessage } from './index';
|
import type { PageScriptToContentScriptMessage } from './index';
|
||||||
|
|
||||||
export type Position = 'left' | 'right' | 'bottom' | 'panel' | 'remote';
|
export type Position = 'window' | 'remote';
|
||||||
|
|
||||||
function post<S, A extends Action<string>>(
|
function post<S, A extends Action<string>>(
|
||||||
message: PageScriptToContentScriptMessage<S, A>,
|
message: PageScriptToContentScriptMessage<S, A>,
|
||||||
|
@ -13,6 +13,6 @@ export default function openWindow(position?: Position) {
|
||||||
post({
|
post({
|
||||||
source: '@devtools-page',
|
source: '@devtools-page',
|
||||||
type: 'OPEN',
|
type: 'OPEN',
|
||||||
position: position || 'right',
|
position: position ?? 'window',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,8 @@ import {
|
||||||
getActionsArray,
|
getActionsArray,
|
||||||
getLocalFilter,
|
getLocalFilter,
|
||||||
} from '@redux-devtools/utils';
|
} from '@redux-devtools/utils';
|
||||||
import throttle from 'lodash/throttle';
|
import { throttle } from 'lodash-es';
|
||||||
import {
|
import { Action, ActionCreator, Dispatch, Reducer, StoreEnhancer } from 'redux';
|
||||||
Action,
|
|
||||||
ActionCreator,
|
|
||||||
Dispatch,
|
|
||||||
PreloadedState,
|
|
||||||
Reducer,
|
|
||||||
StoreEnhancer,
|
|
||||||
StoreEnhancerStoreCreator,
|
|
||||||
} from 'redux';
|
|
||||||
import Immutable from 'immutable';
|
import Immutable from 'immutable';
|
||||||
import {
|
import {
|
||||||
EnhancedStore,
|
EnhancedStore,
|
||||||
|
@ -440,6 +432,13 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
|
||||||
serializeAction,
|
serializeAction,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
case 'OPTIONS':
|
||||||
|
window.devToolsOptions = Object.assign(
|
||||||
|
window.devToolsOptions || {},
|
||||||
|
message.options,
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,32 +525,26 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
|
||||||
relayState(liftedState);
|
relayState(liftedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
const enhance =
|
const enhance = (): StoreEnhancer => (next) => {
|
||||||
(): StoreEnhancer =>
|
return <S2, A2 extends Action<string>, PreloadedState>(
|
||||||
<NextExt, NextStateExt>(
|
reducer_: Reducer<S2, A2, PreloadedState>,
|
||||||
next: StoreEnhancerStoreCreator<NextExt, NextStateExt>,
|
initialState_?: PreloadedState | undefined,
|
||||||
): any => {
|
|
||||||
return <S2 extends S, A2 extends A>(
|
|
||||||
reducer_: Reducer<S2, A2>,
|
|
||||||
initialState_?: PreloadedState<S2>,
|
|
||||||
) => {
|
) => {
|
||||||
if (!isAllowed(window.devToolsOptions)) {
|
if (!isAllowed(window.devToolsOptions)) {
|
||||||
return next(reducer_, initialState_);
|
return next(reducer_, initialState_);
|
||||||
}
|
}
|
||||||
|
|
||||||
store = stores[instanceId] = configureStore(
|
store = stores[instanceId] = (
|
||||||
next as StoreEnhancerStoreCreator,
|
configureStore(next, monitor.reducer, {
|
||||||
monitor.reducer,
|
|
||||||
{
|
|
||||||
...config,
|
...config,
|
||||||
maxAge: getMaxAge as any,
|
maxAge: getMaxAge as any,
|
||||||
},
|
}) as any
|
||||||
)(reducer_, initialState_) as any;
|
)(reducer_, initialState_) as any;
|
||||||
|
|
||||||
if (isInIframe()) setTimeout(init, 3000);
|
if (isInIframe()) setTimeout(init, 3000);
|
||||||
else init();
|
else init();
|
||||||
|
|
||||||
return store;
|
return store as any;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -598,11 +591,11 @@ export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
|
||||||
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
|
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
|
||||||
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
|
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
|
||||||
: never
|
: never
|
||||||
: unknown;
|
: {};
|
||||||
|
|
||||||
const extensionCompose =
|
const extensionCompose =
|
||||||
(config: Config) =>
|
(config: Config) =>
|
||||||
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
<StoreEnhancers extends readonly StoreEnhancer[]>(
|
||||||
...funcs: StoreEnhancers
|
...funcs: StoreEnhancers
|
||||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {
|
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {
|
||||||
// @ts-ignore FIXME
|
// @ts-ignore FIXME
|
||||||
|
@ -619,10 +612,10 @@ const extensionCompose =
|
||||||
interface ReduxDevtoolsExtensionCompose {
|
interface ReduxDevtoolsExtensionCompose {
|
||||||
(
|
(
|
||||||
config: Config,
|
config: Config,
|
||||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
): <StoreEnhancers extends readonly StoreEnhancer[]>(
|
||||||
...funcs: StoreEnhancers
|
...funcs: StoreEnhancers
|
||||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||||
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
<StoreEnhancers extends readonly StoreEnhancer[]>(
|
||||||
...funcs: StoreEnhancers
|
...funcs: StoreEnhancers
|
||||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||||
}
|
}
|
||||||
|
@ -635,24 +628,22 @@ declare global {
|
||||||
|
|
||||||
function reduxDevtoolsExtensionCompose(
|
function reduxDevtoolsExtensionCompose(
|
||||||
config: Config,
|
config: Config,
|
||||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
): <StoreEnhancers extends readonly StoreEnhancer[]>(
|
||||||
...funcs: StoreEnhancers
|
...funcs: StoreEnhancers
|
||||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||||
function reduxDevtoolsExtensionCompose<
|
function reduxDevtoolsExtensionCompose<
|
||||||
StoreEnhancers extends readonly StoreEnhancer<unknown>[],
|
StoreEnhancers extends readonly StoreEnhancer[],
|
||||||
>(
|
>(
|
||||||
...funcs: StoreEnhancers
|
...funcs: StoreEnhancers
|
||||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||||
function reduxDevtoolsExtensionCompose(
|
function reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) {
|
||||||
...funcs: [Config] | StoreEnhancer<unknown>[]
|
|
||||||
) {
|
|
||||||
if (funcs.length === 0) {
|
if (funcs.length === 0) {
|
||||||
return __REDUX_DEVTOOLS_EXTENSION__();
|
return __REDUX_DEVTOOLS_EXTENSION__();
|
||||||
}
|
}
|
||||||
if (funcs.length === 1 && typeof funcs[0] === 'object') {
|
if (funcs.length === 1 && typeof funcs[0] === 'object') {
|
||||||
return extensionCompose(funcs[0]);
|
return extensionCompose(funcs[0]);
|
||||||
}
|
}
|
||||||
return extensionCompose({})(...(funcs as StoreEnhancer<unknown>[]));
|
return extensionCompose({})(...(funcs as StoreEnhancer[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;
|
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
// @ts-ignore
|
|
||||||
import script from '../dist/page.bundle.js';
|
|
||||||
|
|
||||||
let s = document.createElement('script');
|
|
||||||
s.type = 'text/javascript';
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
s.appendChild(document.createTextNode(script));
|
|
||||||
(document.head || document.documentElement).appendChild(s);
|
|
||||||
s.parentNode!.removeChild(s);
|
|
||||||
} else {
|
|
||||||
s.src = chrome.extension.getURL('page.bundle.js');
|
|
||||||
s.onload = function () {
|
|
||||||
(this as HTMLScriptElement).parentNode!.removeChild(
|
|
||||||
this as HTMLScriptElement,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
(document.head || document.documentElement).appendChild(s);
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
|
||||||
import { Provider } from 'react-redux';
|
|
||||||
import { PersistGate } from 'redux-persist/integration/react';
|
|
||||||
import { UPDATE_STATE } from '@redux-devtools/app';
|
|
||||||
import App from '../app/App';
|
|
||||||
import configureStore from './store/windowStore';
|
|
||||||
import type { MonitorMessage } from '../background/store/apiMiddleware';
|
|
||||||
|
|
||||||
const position = location.hash;
|
|
||||||
|
|
||||||
chrome.runtime.getBackgroundPage((window) => {
|
|
||||||
const { store } = window!;
|
|
||||||
const { store: localStore, persistor } = configureStore(store, position);
|
|
||||||
let name = 'monitor';
|
|
||||||
if (chrome && chrome.devtools && chrome.devtools.inspectedWindow) {
|
|
||||||
name += chrome.devtools.inspectedWindow.tabId;
|
|
||||||
}
|
|
||||||
const bg = chrome.runtime.connect({ name });
|
|
||||||
const update = (action?: MonitorMessage) => {
|
|
||||||
localStore.dispatch(action || { type: UPDATE_STATE });
|
|
||||||
};
|
|
||||||
bg.onMessage.addListener(update);
|
|
||||||
update();
|
|
||||||
|
|
||||||
const root = createRoot(document.getElementById('root')!);
|
|
||||||
root.render(
|
|
||||||
<Provider store={localStore}>
|
|
||||||
<PersistGate loading={null} persistor={persistor}>
|
|
||||||
<App position={position} />
|
|
||||||
</PersistGate>
|
|
||||||
</Provider>,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (position === '#popup') document.body.style.minWidth = '760px';
|
|
||||||
if (position !== '#popup') document.body.style.minHeight = '100%';
|
|
|
@ -1,50 +0,0 @@
|
||||||
import { Dispatch, MiddlewareAPI } from 'redux';
|
|
||||||
import {
|
|
||||||
SELECT_INSTANCE,
|
|
||||||
StoreAction,
|
|
||||||
StoreState,
|
|
||||||
UPDATE_STATE,
|
|
||||||
} from '@redux-devtools/app';
|
|
||||||
|
|
||||||
function selectInstance(
|
|
||||||
tabId: number,
|
|
||||||
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
|
|
||||||
next: Dispatch<StoreAction>,
|
|
||||||
) {
|
|
||||||
const instances = store.getState().instances;
|
|
||||||
if (instances.current === 'default') return;
|
|
||||||
const connections = instances.connections[tabId];
|
|
||||||
if (connections && connections.length === 1) {
|
|
||||||
next({ type: SELECT_INSTANCE, selected: connections[0] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCurrentTabId(next: (tabId: number) => void) {
|
|
||||||
chrome.tabs.query(
|
|
||||||
{
|
|
||||||
active: true,
|
|
||||||
lastFocusedWindow: true,
|
|
||||||
},
|
|
||||||
(tabs) => {
|
|
||||||
const tab = tabs[0];
|
|
||||||
if (!tab) return;
|
|
||||||
next(tab.id!);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function popupSelector(
|
|
||||||
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
|
|
||||||
) {
|
|
||||||
return (next: Dispatch<StoreAction>) => (action: StoreAction) => {
|
|
||||||
const result = next(action);
|
|
||||||
if (action.type === UPDATE_STATE) {
|
|
||||||
if (chrome.devtools && chrome.devtools.inspectedWindow) {
|
|
||||||
selectInstance(chrome.devtools.inspectedWindow.tabId, store, next);
|
|
||||||
} else {
|
|
||||||
getCurrentTabId((tabId) => selectInstance(tabId, store, next));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import {
|
|
||||||
instancesInitialState,
|
|
||||||
dispatchAction,
|
|
||||||
UPDATE_STATE,
|
|
||||||
SELECT_INSTANCE,
|
|
||||||
LIFTED_ACTION,
|
|
||||||
SET_PERSIST,
|
|
||||||
} from '@redux-devtools/app';
|
|
||||||
import type {
|
|
||||||
ExpandedUpdateStateAction,
|
|
||||||
WindowStoreAction,
|
|
||||||
} from './windowStore';
|
|
||||||
|
|
||||||
export default function instances(
|
|
||||||
state = instancesInitialState,
|
|
||||||
action: WindowStoreAction,
|
|
||||||
) {
|
|
||||||
switch (action.type) {
|
|
||||||
case UPDATE_STATE:
|
|
||||||
return {
|
|
||||||
...(action as ExpandedUpdateStateAction).instances,
|
|
||||||
selected: state.selected,
|
|
||||||
};
|
|
||||||
case LIFTED_ACTION:
|
|
||||||
if (action.message === 'DISPATCH') return dispatchAction(state, action);
|
|
||||||
return state;
|
|
||||||
case SELECT_INSTANCE:
|
|
||||||
return { ...state, selected: action.selected };
|
|
||||||
case SET_PERSIST:
|
|
||||||
return { ...state, persisted: action.payload };
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { combineReducers, Reducer } from 'redux';
|
|
||||||
import {
|
|
||||||
connection,
|
|
||||||
monitor,
|
|
||||||
notification,
|
|
||||||
reports,
|
|
||||||
section,
|
|
||||||
socket,
|
|
||||||
theme,
|
|
||||||
stateTreeSettings,
|
|
||||||
StoreState,
|
|
||||||
} from '@redux-devtools/app';
|
|
||||||
import instances from './instancesReducer';
|
|
||||||
import type { WindowStoreAction } from './windowStore';
|
|
||||||
|
|
||||||
const rootReducer: Reducer<StoreState, WindowStoreAction> =
|
|
||||||
combineReducers<StoreState>({
|
|
||||||
instances,
|
|
||||||
monitor,
|
|
||||||
socket,
|
|
||||||
reports,
|
|
||||||
notification,
|
|
||||||
section,
|
|
||||||
theme,
|
|
||||||
connection,
|
|
||||||
stateTreeSettings,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default rootReducer;
|
|
|
@ -1,81 +0,0 @@
|
||||||
import {
|
|
||||||
createStore,
|
|
||||||
compose,
|
|
||||||
applyMiddleware,
|
|
||||||
Store,
|
|
||||||
StoreEnhancer,
|
|
||||||
Reducer,
|
|
||||||
} from 'redux';
|
|
||||||
import localForage from 'localforage';
|
|
||||||
import { persistReducer, persistStore } from 'redux-persist';
|
|
||||||
import {
|
|
||||||
api,
|
|
||||||
CONNECT_REQUEST,
|
|
||||||
exportStateMiddleware,
|
|
||||||
InstancesState,
|
|
||||||
StoreActionWithoutUpdateState,
|
|
||||||
StoreState,
|
|
||||||
UpdateStateAction,
|
|
||||||
} from '@redux-devtools/app';
|
|
||||||
import syncStores from './windowSyncMiddleware';
|
|
||||||
import instanceSelector from './instanceSelectorMiddleware';
|
|
||||||
import rootReducer from './windowReducer';
|
|
||||||
import type { BackgroundState } from '../../background/store/backgroundReducer';
|
|
||||||
import type { BackgroundAction } from '../../background/store/backgroundStore';
|
|
||||||
import type {
|
|
||||||
EmptyUpdateStateAction,
|
|
||||||
NAAction,
|
|
||||||
} from '../../background/store/apiMiddleware';
|
|
||||||
|
|
||||||
export interface ExpandedUpdateStateAction extends UpdateStateAction {
|
|
||||||
readonly instances: InstancesState;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WindowStoreAction =
|
|
||||||
| StoreActionWithoutUpdateState
|
|
||||||
| ExpandedUpdateStateAction
|
|
||||||
| NAAction
|
|
||||||
| EmptyUpdateStateAction;
|
|
||||||
|
|
||||||
const persistConfig = {
|
|
||||||
key: 'redux-devtools',
|
|
||||||
blacklist: ['instances', 'socket'],
|
|
||||||
storage: localForage,
|
|
||||||
};
|
|
||||||
|
|
||||||
const persistedReducer: Reducer<StoreState, WindowStoreAction> = persistReducer(
|
|
||||||
persistConfig,
|
|
||||||
rootReducer,
|
|
||||||
) as any;
|
|
||||||
|
|
||||||
export default function configureStore(
|
|
||||||
baseStore: Store<BackgroundState, BackgroundAction>,
|
|
||||||
position: string,
|
|
||||||
) {
|
|
||||||
let enhancer: StoreEnhancer;
|
|
||||||
const middlewares = [exportStateMiddleware, api, syncStores(baseStore)];
|
|
||||||
if (!position || position === '#popup') {
|
|
||||||
// select current tab instance for devPanel and pageAction
|
|
||||||
middlewares.push(instanceSelector);
|
|
||||||
}
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
|
||||||
enhancer = applyMiddleware(...middlewares);
|
|
||||||
} else {
|
|
||||||
enhancer = compose(
|
|
||||||
applyMiddleware(...middlewares),
|
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION__
|
|
||||||
? window.__REDUX_DEVTOOLS_EXTENSION__()
|
|
||||||
: (noop: unknown) => noop,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const store = createStore(persistedReducer, enhancer);
|
|
||||||
const persistor = persistStore(store, null, () => {
|
|
||||||
if (store.getState().connection.type !== 'disabled') {
|
|
||||||
store.dispatch({
|
|
||||||
type: CONNECT_REQUEST,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return { store, persistor };
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import {
|
|
||||||
getActiveInstance,
|
|
||||||
LIFTED_ACTION,
|
|
||||||
StoreAction,
|
|
||||||
StoreState,
|
|
||||||
TOGGLE_PERSIST,
|
|
||||||
UPDATE_STATE,
|
|
||||||
} from '@redux-devtools/app';
|
|
||||||
import { Dispatch, MiddlewareAPI, Store } from 'redux';
|
|
||||||
import type { BackgroundState } from '../../background/store/backgroundReducer';
|
|
||||||
import type { WindowStoreAction } from './windowStore';
|
|
||||||
import type { BackgroundAction } from '../../background/store/backgroundStore';
|
|
||||||
|
|
||||||
const syncStores =
|
|
||||||
(baseStore: Store<BackgroundState, BackgroundAction>) =>
|
|
||||||
(store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>) =>
|
|
||||||
(next: Dispatch<WindowStoreAction>) =>
|
|
||||||
(action: StoreAction) => {
|
|
||||||
if (action.type === UPDATE_STATE) {
|
|
||||||
return next({
|
|
||||||
...action,
|
|
||||||
instances: baseStore.getState().instances,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (action.type === LIFTED_ACTION || action.type === TOGGLE_PERSIST) {
|
|
||||||
const instances = store.getState().instances;
|
|
||||||
const instanceId = getActiveInstance(instances);
|
|
||||||
const id = instances.options[instanceId].connectionId;
|
|
||||||
baseStore.dispatch({ ...action, instanceId, id } as any);
|
|
||||||
}
|
|
||||||
return next(action);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default syncStores;
|
|
|
@ -1,18 +0,0 @@
|
||||||
doctype html
|
|
||||||
|
|
||||||
html
|
|
||||||
head
|
|
||||||
meta(charset='UTF-8')
|
|
||||||
title Redux DevTools
|
|
||||||
include ../style.pug
|
|
||||||
|
|
||||||
body
|
|
||||||
#root
|
|
||||||
div(style='position: relative')
|
|
||||||
img(
|
|
||||||
src='/img/loading.svg',
|
|
||||||
height=300, width=350,
|
|
||||||
style='position: absolute; top: 50%; left: 50%; margin-top: -175px; margin-left: -175px;'
|
|
||||||
)
|
|
||||||
link(href='/window.bundle.css', rel='stylesheet')
|
|
||||||
script(src='/window.bundle.js')
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen, within } from '@testing-library/react';
|
import { render, screen, within } from '@testing-library/react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import configureStore from '../../../src/window/store/windowStore';
|
import configureStore from '../../../src/devpanel/store/panelStore';
|
||||||
import App from '../../../src/app/App';
|
import App from '../../../src/app/App';
|
||||||
|
|
||||||
Object.defineProperty(window, 'matchMedia', {
|
Object.defineProperty(window, 'matchMedia', {
|
||||||
|
|
|
@ -20,16 +20,7 @@ describe('API', () => {
|
||||||
expect(message).toEqual({
|
expect(message).toEqual({
|
||||||
source: '@devtools-page',
|
source: '@devtools-page',
|
||||||
type: 'OPEN',
|
type: 'OPEN',
|
||||||
position: 'right',
|
position: 'window',
|
||||||
});
|
|
||||||
|
|
||||||
message = await listenMessage(() => {
|
|
||||||
window.__REDUX_DEVTOOLS_EXTENSION__.open('left');
|
|
||||||
});
|
|
||||||
expect(message).toEqual({
|
|
||||||
source: '@devtools-page',
|
|
||||||
type: 'OPEN',
|
|
||||||
position: 'left',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import '@babel/polyfill';
|
|
||||||
import { createStore, compose } from 'redux';
|
import { createStore, compose } from 'redux';
|
||||||
import { insertScript, listenMessage } from '../../utils/inject';
|
import { insertScript, listenMessage } from '../../utils/inject';
|
||||||
import '../../../src/pageScript';
|
import '../../../src/pageScript';
|
||||||
|
|
|
@ -27,9 +27,9 @@ describe('Chrome extension', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should open extension's window", async () => {
|
it("should open extension's window", async () => {
|
||||||
await driver.get(`chrome-extension://${extensionId}/window.html#left`);
|
await driver.get(`chrome-extension://${extensionId}/devpanel.html`);
|
||||||
const url = await driver.getCurrentUrl();
|
const url = await driver.getCurrentUrl();
|
||||||
expect(url).toBe(`chrome-extension://${extensionId}/window.html#left`);
|
expect(url).toBe(`chrome-extension://${extensionId}/devpanel.html`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should match document title', async () => {
|
it('should match document title', async () => {
|
||||||
|
@ -37,25 +37,6 @@ describe('Chrome extension', function () {
|
||||||
expect(title).toBe('Redux DevTools');
|
expect(title).toBe('Redux DevTools');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should contain inspector monitor's component", async () => {
|
|
||||||
await delay(1000);
|
|
||||||
const val = await driver
|
|
||||||
.findElement(webdriver.By.xpath('//div[@data-testid="inspector"]'))
|
|
||||||
.getText();
|
|
||||||
expect(val).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should contain an empty actions list', async () => {
|
|
||||||
const val = await driver
|
|
||||||
.findElement(webdriver.By.xpath('//div[@data-testid="actionListRows"]'))
|
|
||||||
.getText();
|
|
||||||
expect(val).toBe('');
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.keys(switchMonitorTests).forEach((description) =>
|
|
||||||
it(description, () => switchMonitorTests[description](driver)),
|
|
||||||
);
|
|
||||||
|
|
||||||
it('should get actions list', async () => {
|
it('should get actions list', async () => {
|
||||||
const url = 'https://zalmoxisus.github.io/examples/router/';
|
const url = 'https://zalmoxisus.github.io/examples/router/';
|
||||||
await driver.executeScript(`window.open('${url}')`);
|
await driver.executeScript(`window.open('${url}')`);
|
||||||
|
@ -68,6 +49,7 @@ describe('Chrome extension', function () {
|
||||||
|
|
||||||
await driver.switchTo().window(tabs[0]);
|
await driver.switchTo().window(tabs[0]);
|
||||||
|
|
||||||
|
await delay(1000);
|
||||||
const result = await driver.wait(
|
const result = await driver.wait(
|
||||||
driver
|
driver
|
||||||
.findElement(webdriver.By.xpath('//div[@data-testid="actionListRows"]'))
|
.findElement(webdriver.By.xpath('//div[@data-testid="actionListRows"]'))
|
||||||
|
@ -80,4 +62,15 @@ describe('Chrome extension', function () {
|
||||||
);
|
);
|
||||||
expect(result).toBeTruthy();
|
expect(result).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should contain inspector monitor's component", async () => {
|
||||||
|
const val = await driver
|
||||||
|
.findElement(webdriver.By.xpath('//div[@data-testid="inspector"]'))
|
||||||
|
.getText();
|
||||||
|
expect(val).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(switchMonitorTests).forEach((description) =>
|
||||||
|
it(description, () => switchMonitorTests[description](driver)),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ import chromedriver from 'chromedriver';
|
||||||
import { switchMonitorTests, delay } from '../utils/e2e';
|
import { switchMonitorTests, delay } from '../utils/e2e';
|
||||||
|
|
||||||
const devPanelPath =
|
const devPanelPath =
|
||||||
'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/window.html';
|
'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/devpanel.html';
|
||||||
|
|
||||||
describe('DevTools panel for Electron', function () {
|
describe('DevTools panel for Electron', function () {
|
||||||
let driver;
|
let driver;
|
||||||
|
@ -52,13 +52,14 @@ describe('DevTools panel for Electron', function () {
|
||||||
if (attempts === 0) {
|
if (attempts === 0) {
|
||||||
return callback('Redux panel not found');
|
return callback('Redux panel not found');
|
||||||
}
|
}
|
||||||
if (UI.inspectorView) {
|
if (EUI.InspectorView) {
|
||||||
const tabs = UI.inspectorView.tabbedPane.tabs;
|
const instance = EUI.InspectorView.InspectorView.instance();
|
||||||
|
const tabs = instance.tabbedPane.tabs;
|
||||||
const idList = tabs.map((tab) => tab.id);
|
const idList = tabs.map((tab) => tab.id);
|
||||||
const reduxPanelId =
|
const reduxPanelId =
|
||||||
'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljdRedux';
|
'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljdRedux';
|
||||||
if (idList.indexOf(reduxPanelId) !== -1) {
|
if (idList.indexOf(reduxPanelId) !== -1) {
|
||||||
UI.inspectorView.showPanel(reduxPanelId);
|
instance.showPanel(reduxPanelId);
|
||||||
return callback(reduxPanelId);
|
return callback(reduxPanelId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import '@babel/polyfill';
|
|
||||||
import { bigArray, bigString, circularData } from './data';
|
import { bigArray, bigString, circularData } from './data';
|
||||||
import { listenMessage } from '../utils/inject';
|
import { listenMessage } from '../utils/inject';
|
||||||
import '../../src/browser/extension/inject/pageScript';
|
import '../../src/browser/extension/inject/pageScript';
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
require('@babel/polyfill');
|
|
||||||
global.chrome = require('sinon-chrome');
|
global.chrome = require('sinon-chrome');
|
||||||
require('@testing-library/jest-dom');
|
require('@testing-library/jest-dom');
|
||||||
|
|
||||||
|
|
41
package.json
41
package.json
|
@ -1,21 +1,21 @@
|
||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.3",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/eslint-parser": "^7.24.1",
|
"@changesets/cli": "^2.27.7",
|
||||||
"@changesets/cli": "^2.27.1",
|
"@eslint/compat": "^1.1.1",
|
||||||
"@nrwl/nx-cloud": "^18.0.0",
|
"@eslint/js": "^8.57.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
"@nrwl/nx-cloud": "^19.0.0",
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-jest": "^27.9.0",
|
"eslint-plugin-jest": "^28.8.1",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.35.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"nx": "^18.1.3",
|
"nx": "^19.6.4",
|
||||||
"prettier": "3.2.5",
|
"prettier": "3.3.3",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.5.4",
|
||||||
|
"typescript-eslint": "^8.3.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
|
@ -24,20 +24,7 @@
|
||||||
"lint:all": "nx run-many --target=lint --all --parallel=1",
|
"lint:all": "nx run-many --target=lint --all --parallel=1",
|
||||||
"test:all": "nx run-many --target=test --all --parallel=1",
|
"test:all": "nx run-many --target=test --all --parallel=1",
|
||||||
"clean:all": "nx run-many --target=clean --all --parallel=1",
|
"clean:all": "nx run-many --target=clean --all --parallel=1",
|
||||||
"release": "pnpm build:all && changeset publish"
|
"release": "pnpm build:all && pnpm publish -r"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"packageManager": "pnpm@9.9.0"
|
||||||
"extension",
|
|
||||||
"packages/*",
|
|
||||||
"packages/d3-state-visualizer/examples/tree",
|
|
||||||
"packages/react-dock/demo",
|
|
||||||
"packages/react-json-tree/examples",
|
|
||||||
"packages/redux-devtools/examples/counter",
|
|
||||||
"packages/redux-devtools/examples/todomvc",
|
|
||||||
"packages/redux-devtools-inspector-monitor/demo",
|
|
||||||
"packages/redux-devtools-inspector-monitor-test-tab/demo",
|
|
||||||
"packages/redux-devtools-rtk-query-monitor/demo",
|
|
||||||
"packages/redux-devtools-slider-monitor/examples/todomvc"
|
|
||||||
],
|
|
||||||
"packageManager": "pnpm@8.15.5"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
examples
|
|
||||||
lib
|
|
|
@ -1,13 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../eslintrc.js.base.json',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts'],
|
|
||||||
extends: '../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
10
packages/d3-state-visualizer/eslint.config.js
Normal file
10
packages/d3-state-visualizer/eslint.config.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import eslintJs from '../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../eslint.ts.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
{
|
||||||
|
ignores: ['examples', 'lib'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -1 +0,0 @@
|
||||||
dist
|
|
|
@ -1,17 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['webpack.config.ts'],
|
|
||||||
extends: '../../../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.webpack.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
15
packages/d3-state-visualizer/examples/tree/eslint.config.mjs
Normal file
15
packages/d3-state-visualizer/examples/tree/eslint.config.mjs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import eslintJs from '../../../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../../../eslint.ts.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
...eslintTs(
|
||||||
|
import.meta.dirname,
|
||||||
|
['webpack.config.ts'],
|
||||||
|
['./tsconfig.webpack.json'],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
ignores: ['dist'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -21,29 +21,25 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
|
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
|
||||||
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack",
|
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit"
|
"type-check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"d3-state-visualizer": "^3.0.0",
|
"d3-state-visualizer": "workspace:^",
|
||||||
"map2tree": "^4.0.0"
|
"map2tree": "workspace:^"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.3",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-env": "^7.24.3",
|
"@babel/preset-env": "^7.25.4",
|
||||||
"@babel/preset-typescript": "^7.24.1",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@types/node": "^20.11.30",
|
"@types/node": "^20.16.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
||||||
"html-webpack-plugin": "^5.6.0",
|
"html-webpack-plugin": "^5.6.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "~5.3.3",
|
"typescript": "~5.5.4",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.94.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^5.0.4"
|
"webpack-dev-server": "^5.0.4"
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepack": "pnpm run clean && pnpm run build",
|
"prepack": "pnpm run clean && pnpm run build",
|
||||||
"prepublish": "pnpm run lint"
|
"prepublish": "pnpm run lint"
|
||||||
|
@ -39,18 +39,14 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"d3": "^7.9.0",
|
"d3": "^7.9.0",
|
||||||
"d3tooltip": "^4.0.0",
|
"d3tooltip": "workspace:^",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"map2tree": "^4.0.0",
|
"map2tree": "workspace:^",
|
||||||
"ramda": "^0.29.1"
|
"ramda": "^0.30.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ramda": "^0.29.11",
|
"@types/ramda": "^0.30.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
"rimraf": "^6.0.1",
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
"typescript": "~5.5.4"
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"rimraf": "^5.0.5",
|
|
||||||
"typescript": "~5.3.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ import { tooltip } from 'd3tooltip';
|
||||||
import type { StyleValue } from 'd3tooltip';
|
import type { StyleValue } from 'd3tooltip';
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
state?: {} | null;
|
state?: {} | null;
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
tree?: Node | {};
|
tree?: Node | {};
|
||||||
|
|
||||||
rootKeyName: string;
|
rootKeyName: string;
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
lib
|
|
|
@ -1,13 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../eslintrc.js.base.json',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts'],
|
|
||||||
extends: '../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
10
packages/d3tooltip/eslint.config.js
Normal file
10
packages/d3tooltip/eslint.config.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import eslintJs from '../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../eslint.ts.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
{
|
||||||
|
ignores: ['lib'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -27,20 +27,16 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepack": "pnpm run clean && pnpm run build",
|
"prepack": "pnpm run clean && pnpm run build",
|
||||||
"prepublish": "pnpm run lint"
|
"prepublish": "pnpm run lint"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"d3": "^7.9.0",
|
"d3": "^7.9.0",
|
||||||
"eslint": "^8.57.0",
|
"rimraf": "^6.0.1",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"typescript": "~5.5.4"
|
||||||
"rimraf": "^5.0.5",
|
|
||||||
"typescript": "~5.3.3"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
lib
|
|
|
@ -1,21 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../eslintrc.js.base.json',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts'],
|
|
||||||
extends: '../../eslintrc.ts.jest.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['test/**/*.ts'],
|
|
||||||
extends: '../../eslintrc.ts.jest.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.test.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
12
packages/map2tree/eslint.config.js
Normal file
12
packages/map2tree/eslint.config.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import eslintJs from '../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../eslint.ts.config.base.mjs';
|
||||||
|
import eslintTsJest from '../../eslint.ts.jest.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
...eslintTsJest(import.meta.dirname),
|
||||||
|
{
|
||||||
|
ignores: ['lib'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -31,7 +31,7 @@
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepack": "pnpm run clean && pnpm run build",
|
"prepack": "pnpm run clean && pnpm run build",
|
||||||
"prepublish": "pnpm run lint && pnpm run test"
|
"prepublish": "pnpm run lint && pnpm run test"
|
||||||
|
@ -42,15 +42,10 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
"immutable": "^4.3.7",
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-jest": "^27.9.0",
|
|
||||||
"immutable": "^4.3.5",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^6.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,9 +45,9 @@ export function map2tree(
|
||||||
root: unknown,
|
root: unknown,
|
||||||
options: { key?: string; pushMethod?: 'push' | 'unshift' } = {},
|
options: { key?: string; pushMethod?: 'push' | 'unshift' } = {},
|
||||||
tree: Node = { name: options.key || 'state', children: [] },
|
tree: Node = { name: options.key || 'state', children: [] },
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
): Node | {} {
|
): Node | {} {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
if (!isPlainObject(root) && root && !(root as { toJS: () => {} }).toJS) {
|
if (!isPlainObject(root) && root && !(root as { toJS: () => {} }).toJS) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -60,13 +60,13 @@ export function map2tree(
|
||||||
}
|
}
|
||||||
|
|
||||||
mapValues(
|
mapValues(
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
root && (root as { toJS: () => {} }).toJS
|
root && (root as { toJS: () => {} }).toJS
|
||||||
? // eslint-disable-next-line @typescript-eslint/ban-types
|
? // eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
(root as { toJS: () => {} }).toJS()
|
(root as { toJS: () => {} }).toJS()
|
||||||
: // eslint-disable-next-line @typescript-eslint/ban-types
|
: // eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
(root as {}),
|
(root as {}),
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
(maybeImmutable: { toJS?: () => {} }, key) => {
|
(maybeImmutable: { toJS?: () => {} }, key) => {
|
||||||
const value =
|
const value =
|
||||||
maybeImmutable && maybeImmutable.toJS
|
maybeImmutable && maybeImmutable.toJS
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
lib
|
|
|
@ -1,21 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../eslintrc.js.base.json',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts'],
|
|
||||||
extends: '../../eslintrc.ts.jest.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['test/**/*.ts'],
|
|
||||||
extends: '../../eslintrc.ts.jest.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.test.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
12
packages/react-base16-styling/eslint.config.js
Normal file
12
packages/react-base16-styling/eslint.config.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import eslintJs from '../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../eslint.ts.config.base.mjs';
|
||||||
|
import eslintTsJest from '../../eslint.ts.jest.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
...eslintTsJest(import.meta.dirname),
|
||||||
|
{
|
||||||
|
ignores: ['lib'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -30,13 +30,13 @@
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepack": "pnpm run clean && pnpm run build",
|
"prepack": "pnpm run clean && pnpm run build",
|
||||||
"prepublish": "pnpm run lint && pnpm run test"
|
"prepublish": "pnpm run lint && pnpm run test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "^4.17.0",
|
"@types/lodash": "^4.17.7",
|
||||||
"color": "^4.2.3",
|
"color": "^4.2.3",
|
||||||
"csstype": "^3.1.3",
|
"csstype": "^3.1.3",
|
||||||
"lodash-es": "^4.17.21"
|
"lodash-es": "^4.17.21"
|
||||||
|
@ -45,15 +45,10 @@
|
||||||
"@types/color": "^3.0.6",
|
"@types/color": "^3.0.6",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-jest": "^27.9.0",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^6.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ const mergeStylings = (
|
||||||
): StylingConfig => {
|
): StylingConfig => {
|
||||||
const keys = Object.keys(defaultStylings);
|
const keys = Object.keys(defaultStylings);
|
||||||
for (const key in customStylings) {
|
for (const key in customStylings) {
|
||||||
if (keys.indexOf(key) === -1) keys.push(key);
|
if (!keys.includes(key)) keys.push(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return keys.reduce(
|
return keys.reduce(
|
||||||
|
@ -241,7 +241,7 @@ export const createStyling: CurriedFunction3<
|
||||||
|
|
||||||
const customStyling = Object.keys(themeOrStyling).reduce(
|
const customStyling = Object.keys(themeOrStyling).reduce(
|
||||||
(s, key) =>
|
(s, key) =>
|
||||||
BASE16_KEYS.indexOf(key) === -1
|
!BASE16_KEYS.includes(key)
|
||||||
? ((s[key] = (themeOrStyling as StylingConfig)[key]), s)
|
? ((s[key] = (themeOrStyling as StylingConfig)[key]), s)
|
||||||
: s,
|
: s,
|
||||||
{} as StylingConfig,
|
{} as StylingConfig,
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
demo
|
|
||||||
lib
|
|
|
@ -1,21 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../eslintrc.js.base.json',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts', '*.tsx'],
|
|
||||||
extends: '../../eslintrc.ts.react.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['test/**/*.ts', 'test/**/*.tsx'],
|
|
||||||
extends: '../../eslintrc.ts.react.jest.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.test.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
|
@ -1 +0,0 @@
|
||||||
dist
|
|
|
@ -1,17 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../../eslintrc.ts.react.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['webpack.config.ts'],
|
|
||||||
extends: '../../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.webpack.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
15
packages/react-dock/demo/eslint.config.mjs
Normal file
15
packages/react-dock/demo/eslint.config.mjs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import eslintJs from '../../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../../eslint.ts.react.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
...eslintTs(
|
||||||
|
import.meta.dirname,
|
||||||
|
['webpack.config.ts'],
|
||||||
|
['./tsconfig.webpack.json'],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
ignores: ['dist'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -6,40 +6,34 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
|
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
|
||||||
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack",
|
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack",
|
||||||
"lint": "eslint . --ext .ts,.tsx",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit"
|
"type-check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-bootstrap": "^2.10.2",
|
"react-bootstrap": "^2.10.4",
|
||||||
"react-dock": "^0.7.0",
|
"react-dock": "workspace:^",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.3.0",
|
||||||
"react-is": "^18.2.0",
|
"react-is": "^18.3.1",
|
||||||
"styled-components": "^5.3.11"
|
"styled-components": "^5.3.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.3",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-env": "^7.24.3",
|
"@babel/preset-env": "^7.25.4",
|
||||||
"@babel/preset-react": "^7.24.1",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@babel/preset-typescript": "^7.24.1",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@types/node": "^20.11.30",
|
"@types/node": "^20.16.3",
|
||||||
"@types/react": "^18.2.72",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-dom": "^18.2.22",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/styled-components": "^5.1.34",
|
"@types/styled-components": "^5.1.34",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-react": "^7.34.1",
|
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
|
||||||
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
||||||
"html-webpack-plugin": "^5.6.0",
|
"html-webpack-plugin": "^5.6.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "~5.3.3",
|
"typescript": "~5.5.4",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.94.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^5.0.4"
|
"webpack-dev-server": "^5.0.4"
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ interface State {
|
||||||
size: number;
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
export default class App extends Component<{}, State> {
|
export default class App extends Component<{}, State> {
|
||||||
state: State = {
|
state: State = {
|
||||||
positionIdx: 0,
|
positionIdx: 0,
|
||||||
|
|
12
packages/react-dock/eslint.config.js
Normal file
12
packages/react-dock/eslint.config.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import eslintJs from '../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTsReact from '../../eslint.ts.react.config.base.mjs';
|
||||||
|
import eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTsReact(import.meta.dirname),
|
||||||
|
...eslintTsReactJest(import.meta.dirname),
|
||||||
|
{
|
||||||
|
ignores: ['demo', 'lib'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -30,7 +30,7 @@
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||||
"lint": "eslint . --ext .ts,.tsx",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepack": "pnpm run clean && pnpm run build",
|
"prepack": "pnpm run clean && pnpm run build",
|
||||||
"prepublish": "pnpm run lint && pnpm run test"
|
"prepublish": "pnpm run lint && pnpm run test"
|
||||||
|
@ -41,22 +41,15 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/react": "^18.2.72",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-test-renderer": "^18.0.7",
|
"@types/react-test-renderer": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-jest": "^27.9.0",
|
|
||||||
"eslint-plugin-react": "^7.34.1",
|
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-test-renderer": "^18.2.0",
|
"react-test-renderer": "^18.3.1",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^6.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.5.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
|
|
@ -385,7 +385,7 @@ export default class Dock extends Component<Props, State> {
|
||||||
|
|
||||||
handleDimClick = () => {
|
handleDimClick = () => {
|
||||||
if (this.props.dimMode === 'opaque') {
|
if (this.props.dimMode === 'opaque') {
|
||||||
this.props.onVisibleChange && this.props.onVisibleChange(false);
|
if (this.props.onVisibleChange) this.props.onVisibleChange(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -471,7 +471,7 @@ export default class Dock extends Component<Props, State> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onSizeChange && this.props.onSizeChange(size);
|
if (this.props.onSizeChange) this.props.onSizeChange(size);
|
||||||
|
|
||||||
if (!isControlled) {
|
if (!isControlled) {
|
||||||
this.setState({ size });
|
this.setState({ size });
|
||||||
|
|
|
@ -48,7 +48,7 @@ function prefixProp<Value>(key: string, value: Value) {
|
||||||
export default function autoprefix(style: CSSProperties) {
|
export default function autoprefix(style: CSSProperties) {
|
||||||
return Object.keys(style).reduce(
|
return Object.keys(style).reduce(
|
||||||
(obj, key) =>
|
(obj, key) =>
|
||||||
vendorSpecificProperties.indexOf(key) !== -1
|
vendorSpecificProperties.includes(key)
|
||||||
? {
|
? {
|
||||||
...obj,
|
...obj,
|
||||||
...prefixProp(key, style[key as keyof CSSProperties]),
|
...prefixProp(key, style[key as keyof CSSProperties]),
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
examples
|
|
||||||
lib
|
|
|
@ -1,29 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../eslintrc.js.base.json',
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['*.ts', '*.tsx'],
|
|
||||||
extends: '../../eslintrc.ts.react.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['test/**/*.ts', 'test/**/*.tsx'],
|
|
||||||
extends: '../../eslintrc.ts.react.jest.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.test.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['webpack.config.umd.ts'],
|
|
||||||
extends: '../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.webpack.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
12
packages/react-json-tree/eslint.config.js
Normal file
12
packages/react-json-tree/eslint.config.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import eslintJs from '../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTsReact from '../../eslint.ts.react.config.base.mjs';
|
||||||
|
import eslintTsReactJest from '../../eslint.ts.react.jest.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTsReact(import.meta.dirname),
|
||||||
|
...eslintTsReactJest(import.meta.dirname),
|
||||||
|
{
|
||||||
|
ignores: ['examples', 'lib'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -1 +0,0 @@
|
||||||
dist
|
|
|
@ -1,17 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: '../../../eslintrc.ts.react.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: true,
|
|
||||||
},
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['webpack.config.ts'],
|
|
||||||
extends: '../../../eslintrc.ts.base.json',
|
|
||||||
parserOptions: {
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
project: ['./tsconfig.webpack.json'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
15
packages/react-json-tree/examples/eslint.config.mjs
Normal file
15
packages/react-json-tree/examples/eslint.config.mjs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import eslintJs from '../../../eslint.js.config.base.mjs';
|
||||||
|
import eslintTs from '../../../eslint.ts.react.config.base.mjs';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...eslintJs,
|
||||||
|
...eslintTs(import.meta.dirname),
|
||||||
|
...eslintTs(
|
||||||
|
import.meta.dirname,
|
||||||
|
['webpack.config.ts'],
|
||||||
|
['./tsconfig.webpack.json'],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
ignores: ['dist'],
|
||||||
|
},
|
||||||
|
];
|
|
@ -15,37 +15,31 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
|
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
|
||||||
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack",
|
"build": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack",
|
||||||
"lint": "eslint . --ext .ts,.tsx",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit"
|
"type-check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"immutable": "^4.3.5",
|
"immutable": "^4.3.7",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-base16-styling": "^0.10.0",
|
"react-base16-styling": "workspace:^",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-json-tree": "^0.19.0"
|
"react-json-tree": "workspace:^"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.3",
|
"@babel/core": "^7.25.2",
|
||||||
"@babel/preset-env": "^7.24.3",
|
"@babel/preset-env": "^7.25.4",
|
||||||
"@babel/preset-react": "^7.24.1",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@babel/preset-typescript": "^7.24.1",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@types/node": "^20.11.30",
|
"@types/node": "^20.16.3",
|
||||||
"@types/react": "^18.2.72",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-dom": "^18.2.22",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-react": "^7.34.1",
|
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
|
||||||
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
"fork-ts-checker-webpack-plugin": "^9.0.2",
|
||||||
"html-webpack-plugin": "^5.6.0",
|
"html-webpack-plugin": "^5.6.0",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"typescript": "~5.3.3",
|
"typescript": "~5.5.4",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.94.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.1.4",
|
||||||
"webpack-dev-server": "^5.0.4"
|
"webpack-dev-server": "^5.0.4"
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,32 +34,25 @@
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"clean": "rimraf lib",
|
"clean": "rimraf lib",
|
||||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||||
"lint": "eslint . --ext .ts,.tsx",
|
"lint": "eslint .",
|
||||||
"type-check": "tsc --noEmit",
|
"type-check": "tsc --noEmit",
|
||||||
"prepack": "pnpm run clean && pnpm run build",
|
"prepack": "pnpm run clean && pnpm run build",
|
||||||
"prepublish": "pnpm run lint && pnpm run test"
|
"prepublish": "pnpm run lint && pnpm run test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/lodash": "^4.17.0",
|
"@types/lodash": "^4.17.7",
|
||||||
"react-base16-styling": "^0.10.0"
|
"react-base16-styling": "workspace:^"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/react": "^18.2.72",
|
"@types/react": "^18.3.5",
|
||||||
"@types/react-test-renderer": "^18.0.7",
|
"@types/react-test-renderer": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
|
||||||
"@typescript-eslint/parser": "^7.4.0",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-prettier": "^9.1.0",
|
|
||||||
"eslint-plugin-jest": "^27.9.0",
|
|
||||||
"eslint-plugin-react": "^7.34.1",
|
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-test-renderer": "^18.2.0",
|
"react-test-renderer": "^18.3.1",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^6.0.1",
|
||||||
"ts-jest": "^29.1.2",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.5.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user