Compare commits

...

159 Commits

Author SHA1 Message Date
renovate[bot]
0cd341fe35
fix(deps): update all non-major dependencies (#1983)
* fix(deps): update all non-major dependencies

* Fix tests

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2026-01-15 16:27:23 -05:00
megos
62cb6ddc25
docs(extension): fix broken relative links in README (#1986) 2026-01-07 09:37:52 -05:00
renovate[bot]
ed6d65bd30
chore(deps): update dependency globals to v17 (#1985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-02 09:54:37 -05:00
renovate[bot]
8f5cf1b5bc
chore(deps): update dependency storybook to ^10.1.10 (#1980)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-24 21:53:55 +00:00
renovate[bot]
21d5699045
chore(deps): lock file maintenance (#1975)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-24 21:42:41 +00:00
renovate[bot]
d609bfb14d
fix(deps): update all non-major dependencies (#1972)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-24 21:26:06 +00:00
renovate[bot]
b350e7bae9
fix(deps): update dependency msw to ^2.12.4 (#1968)
* fix(deps): update dependency msw to ^2.12.4

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-12-24 21:15:59 +00:00
renovate[bot]
35aa092d45
chore(deps): update actions/upload-artifact action to v6 (#1979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-24 21:07:17 +00:00
renovate[bot]
102c21d43e
fix(deps): update dependency socketcluster-server to v20 (#1965)
* fix(deps): update dependency socketcluster-client to v20

* fix(deps): update dependency socketcluster-server to v20

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-12-24 20:56:33 +00:00
renovate[bot]
b8219c2afc
fix(deps): update dependency body-parser to ^2.2.1 (#1971)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 15:22:57 +00:00
renovate[bot]
1e701e45cb
chore(deps): lock file maintenance (#1969)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 15:13:05 +00:00
renovate[bot]
78ed3b1efe
fix(deps): update all non-major dependencies (#1966)
* fix(deps): update all non-major dependencies

* Format

* Updates

* Update

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-12-01 09:57:40 -05:00
renovate[bot]
fbdbb56d19
chore(deps): update actions/checkout action to v6 (#1967)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 16:05:50 -05:00
renovate[bot]
c7e77652c2
fix(deps): update dependency @apollo/server to v5 (#1909)
* fix(deps): update dependency @apollo/server to v5

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-11-20 14:53:56 +00:00
renovate[bot]
558e2ecfd3
fix(deps): update dependency msw to ^2.12.2 (#1958)
* fix(deps): update dependency msw to ^2.12.2

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-11-20 14:42:37 +00:00
renovate[bot]
d0e04165ab
chore(deps): lock file maintenance (#1961)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 14:20:24 +00:00
renovate[bot]
aebfca4f93
fix(deps): update all non-major dependencies (#1957)
* fix(deps): update all non-major dependencies

* Fix

* Fix

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-11-20 14:02:42 +00:00
renovate[bot]
56de415db0
fix(deps): update dependency open to v11 (#1959)
* fix(deps): update dependency open to v11

* Update Node.js engine requirement to version 20

* Update @redux-devtools/cli to major version

Updated @redux-devtools/cli dependency version to major and required Node.js 20.

* Format

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-11-15 13:00:49 +00:00
renovate[bot]
36f1f36471
fix(deps): update dependency msw to ^2.12.1 (#1956)
* fix(deps): update dependency msw to ^2.12.1

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-11-12 15:03:38 +00:00
renovate[bot]
1039d6c827
chore(deps): lock file maintenance (#1955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-12 14:27:26 +00:00
renovate[bot]
ebaf7cf102
fix(deps): update all non-major dependencies (#1953)
* fix(deps): update all non-major dependencies

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-11-12 08:50:25 -05:00
renovate[bot]
a4343c3116
fix(deps): update rjsf monorepo to v6 (major) (#1954)
* fix(deps): update rjsf monorepo to v6

* Update snapshots

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-31 23:55:00 +00:00
renovate[bot]
75cafed485
chore(deps): update storybook monorepo to v10 (major) (#1951)
* chore(deps): update storybook monorepo to v10

* ESM updates

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-30 14:31:34 -04:00
renovate[bot]
a663401e42
chore(deps): update dependency vite to ^7.1.12 (#1952)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 15:18:37 +00:00
renovate[bot]
60a027e016
chore(deps): lock file maintenance (#1942)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 10:32:34 -04:00
renovate[bot]
85e0eb9a67
fix(deps): update all non-major dependencies (#1941)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-30 10:14:30 -04:00
renovate[bot]
8e6014f9d3
fix(deps): update dependency msw to ^2.11.6 (#1943)
* fix(deps): update dependency msw to ^2.11.6

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-30 14:02:39 +00:00
renovate[bot]
70c98a0c05
chore(deps): update dependency @types/node to v24 (#1949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 11:44:48 -04:00
renovate[bot]
ebaf3e0516
chore(deps): update actions/upload-artifact action to v5 (#1948)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 11:06:26 -04:00
renovate[bot]
10f112c0ee
chore(deps): update dependency vite to ^7.1.10 (#1940)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 15:11:24 +00:00
renovate[bot]
ca3782c545
chore(deps): update dependency eslint-plugin-react-hooks to v7 (#1937)
* chore(deps): update dependency eslint-plugin-react-hooks to v7

* Update

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-14 14:58:12 +00:00
renovate[bot]
9d4924ef1d
chore(deps): update actions/setup-node action to v6 (#1939)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-14 14:13:52 +00:00
renovate[bot]
16087352e1
fix(deps): update dependency msw to ^2.11.5 (#1933)
* fix(deps): update dependency msw to ^2.11.5

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-14 10:05:45 -04:00
renovate[bot]
f80b555457
chore(deps): lock file maintenance (#1935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 09:36:22 -04:00
renovate[bot]
c7a9b746d5
fix(deps): update all non-major dependencies (#1929)
* fix(deps): update all non-major dependencies

* isolatedModules

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-10-14 09:03:32 -04:00
renovate[bot]
f0330162e6
chore(deps): update dependency @types/uuid to v11 (#1930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-16 22:18:55 +00:00
github-actions[bot]
531aa338e7
Version Packages (#1884)
* Version Packages

* Trigger build

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-09-15 15:52:06 +00:00
renovate[bot]
8308db6832
fix(deps): update dependency msw to ^2.11.2 (#1905)
* fix(deps): update dependency msw to ^2.11.2

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-09-15 15:25:27 +00:00
renovate[bot]
4e44c2ca50
fix(deps): update dependency uuid to v13 (#1926)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-09-15 15:05:51 +00:00
renovate[bot]
4e81dc99c4
chore(deps): lock file maintenance (#1925)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 14:52:46 +00:00
renovate[bot]
e9e6b33a6d
chore(deps): update all non-major dependencies to ^9.1.6 (#1928)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 14:26:00 +00:00
renovate[bot]
20883e5bdf
fix(deps): update all non-major dependencies (#1918)
* fix(deps): update all non-major dependencies

* Update non-major dependencies in changeset

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-09-15 14:03:16 +00:00
renovate[bot]
0e9528ea37
chore(deps): update dependency vite to v7.1.5 [security] (#1927)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-09 17:48:00 -04:00
renovate[bot]
e327727f91
fix(deps): update dependency uuid to v12 (#1924)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-05 14:19:16 -04:00
renovate[bot]
4a616983aa
chore(deps): update actions/setup-node action to v5 (#1922)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-04 08:35:02 -04:00
renovate[bot]
13e65e0f73
chore(deps): lock file maintenance (#1904)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-09-01 16:26:37 +00:00
renovate[bot]
c3e35815d8
chore(deps): update all non-major dependencies (#1917)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-01 12:18:56 -04:00
renovate[bot]
b1e2d4bd58
fix(deps): update all non-major dependencies (#1901)
* fix(deps): update all non-major dependencies

* Update snapshots

* Update snpashots

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-09-01 11:57:43 -04:00
renovate[bot]
68f82b6994
chore(deps): update actions/checkout action to v5 (#1914)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 12:48:53 -04:00
renovate[bot]
30308f54ab
chore(deps): update dependency cross-env to v10 (#1910)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-08-08 01:05:33 +00:00
renovate[bot]
5b28b69261
chore(deps): update dependency typescript to ~5.9.2 (#1912)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-07 20:57:36 -04:00
Nathan Bierema
7a48268a74
Dedupe pnpm (#1903) 2025-06-28 14:10:19 +00:00
renovate[bot]
fa20f09fc1
chore(deps): update dependency vite to v7 (#1899)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 13:06:49 +00:00
renovate[bot]
1e0d09251b
chore(deps): lock file maintenance (#1898)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 12:57:06 +00:00
renovate[bot]
2b7e1b890a
fix(deps): update all non-major dependencies (#1894)
* fix(deps): update all non-major dependencies

* Format

* Dedupe

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-06-24 08:46:36 -04:00
renovate[bot]
119864cd95
chore(deps): update dependency eslint-plugin-jest to v29 (#1896)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 09:23:54 -04:00
renovate[bot]
dfa6c937c3
chore(deps): update jest monorepo to v30 (major) (#1893)
* chore(deps): update jest monorepo to v30

* Update snapshot

* Update

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-06-17 20:20:57 -04:00
renovate[bot]
8b554db5bf
chore(deps): lock file maintenance (#1886)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-18 00:06:25 +00:00
renovate[bot]
842419b802
fix(deps): update all non-major dependencies (#1872)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 23:53:45 +00:00
renovate[bot]
1e3fb5e27a
fix(deps): update dependency express to v5 (#1779)
* fix(deps): update dependency express to v5

* Update

* Lint

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-06-17 23:43:28 +00:00
renovate[bot]
da5e9f0c1a
fix(deps): update dependency msw to ^2.10.2 (#1888)
* fix(deps): update dependency msw to ^2.10.2

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-06-17 23:32:57 +00:00
Nathan Bierema
54c40135e5
Use Chrome for Testing for Selenium testing (#1892)
* Use Chrome for Testing to fix Selenium tests

* Unintentional
2025-06-17 23:03:29 +00:00
Nathan Bierema
61632768a7
Replace styled-components with Emotion (#1883)
* Replace styled-components with Emotion in ui

* react-dock

* Remainder

* Fix

* Format

* Update snapshots

* Create bright-sheep-joke.md
2025-06-01 13:59:13 +00:00
renovate[bot]
585d6b9220
fix(deps): update dependency @chakra-ui/react to v3 (#1802)
* fix(deps): update dependency @chakra-ui/react to v3

* Remove unnecessary packages

* Add snippets

* Updates

* Remove unused

* Remove ColorModeProvider?

* Fix

* Fix

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-31 18:33:19 +00:00
renovate[bot]
6468c48b75
fix(deps): update dependency react-router-dom to v7 (#1881)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-31 16:10:19 +00:00
renovate[bot]
41f3c1a7b6
fix(deps): update dependency framer-motion to v12 (#1880)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-31 15:59:03 +00:00
renovate[bot]
c82e511929
fix(deps): update react monorepo (major) (#1801)
* fix(deps): update react monorepo

* Updates

* Update

* Update

* Update

* Updates

* Updates

* Update

* Remove usages of react-test-renderer

* Fix

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-31 14:34:45 +00:00
renovate[bot]
832f4dc195
chore(deps): update storybook monorepo to v9 (major) (#1876)
* chore(deps): update storybook monorepo to v9

* Updates

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-31 13:24:58 +00:00
renovate[bot]
4b35476610
fix(deps): update dependency msw to ^2.8.7 (#1874)
* fix(deps): update dependency msw to ^2.8.7

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-31 12:52:38 +00:00
renovate[bot]
7873dd23ae
chore(deps): update pnpm to v10 (#1868)
* chore(deps): update pnpm to v10

* Build?

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-31 12:34:05 +00:00
renovate[bot]
9444ca7e87
fix(deps): update dnd-kit monorepo (#1871)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-23 23:09:17 +00:00
renovate[bot]
b2f01026cb
fix(deps): update dependency uuid to v11 (#1870)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-23 22:54:20 +00:00
renovate[bot]
04c234dd49
fix(deps): update dependency color to v5 (#1869)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-23 22:28:15 +00:00
renovate[bot]
c394803622
chore(deps): update dependency stylelint-config-standard to v38 (#1867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-23 18:02:31 -04:00
renovate[bot]
fd56ac7d92
chore(deps): update dependency globals to v16 (#1866)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-23 21:23:59 +00:00
renovate[bot]
65dce0864e
chore(deps): update dependency copy-webpack-plugin to v13 (#1865)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-23 21:13:20 +00:00
renovate[bot]
e02cfd327c
fix(deps): update dependency msw to ^2.8.4 (#1856)
* fix(deps): update dependency msw to ^2.8.4

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-23 21:02:42 +00:00
renovate[bot]
9ddcef672f
chore(deps): lock file maintenance (#1864)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-23 20:50:40 +00:00
renovate[bot]
3f52f16473
fix(deps): update all non-major dependencies (#1861)
* fix(deps): update all non-major dependencies

* Dedupe

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-23 20:31:45 +00:00
renovate[bot]
9f12777827
chore(deps): lock file maintenance (#1860)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-08 02:45:30 +00:00
renovate[bot]
5dc8611c38
fix(deps): update all non-major dependencies (#1843)
* fix(deps): update all non-major dependencies

* Fix lint

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-05-08 02:27:02 +00:00
github-actions[bot]
1c5df1ee32
Version Packages (#1851)
* Version Packages

* Bump extension version number

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-04-03 00:36:05 +00:00
renovate[bot]
3fc48a226b
fix(deps): update dependency @babel/runtime to v7.26.10 [security] (#1850)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 18:56:21 +00:00
Mark Erikson
17b55ef99f
Handle api.provided state changes in RTKQ 2.6.2 (#1848)
* Handle api.provided state changes in RTKQ 2.6.2

* Create little-melons-grow.md

---------

Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-04-02 18:46:52 +00:00
renovate[bot]
73a01cc5a7
chore(deps): update dependency @storybook/addon-webpack5-compiler-swc to v3 (#1849)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 18:38:41 +00:00
renovate[bot]
07e8f2c3ad
chore(deps): update dependency babel-loader to v10 (#1845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 17:23:47 -05:00
renovate[bot]
8c563d71bb
chore(deps): update dependency typescript to ~5.8.2 (#1844)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 22:10:41 +00:00
renovate[bot]
d730ea185f
fix(deps): update dependency immutable to v5 (#1799)
* fix(deps): update dependency immutable to v5

* Updates

* Updates

* Updates

* Fix lint

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-03-05 22:00:27 +00:00
renovate[bot]
6df66b7320
fix(deps): update dependency msw to ^2.7.3 (#1841)
* fix(deps): update dependency msw to ^2.7.3

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-03-05 20:40:41 +00:00
renovate[bot]
3c90662cfa
chore(deps): lock file maintenance (#1842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 14:49:14 -05:00
renovate[bot]
763bf937a4
fix(deps): update all non-major dependencies (#1840)
* fix(deps): update all non-major dependencies

* Dedupe

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-03-05 19:15:25 +00:00
github-actions[bot]
8ec2b303ee
Version Packages (#1838)
* Version Packages

* Trigger build

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-03-01 16:37:28 -05:00
Nathan Bierema
91f21b2ffc
Fix compatibility of createDevTools with React 19 types (#1837)
* Fix compatibility of createDevTools with React 19 types

* Create fluffy-keys-doubt.md
2025-03-01 20:09:01 +00:00
github-actions[bot]
ff60266836
Version Packages (#1836)
* Version Packages

* Fix version numbers

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-03-01 12:09:02 -05:00
Nathan Bierema
6830118951
Add React 19 to peer deps (#1835)
* Add React 19 to peer deps

* Create moody-crabs-kick.md

* Update moody-crabs-kick.md
2025-03-01 11:44:15 -05:00
renovate[bot]
cc7ec13fb9
chore(deps): lock file maintenance (#1834)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-27 21:53:49 +00:00
renovate[bot]
e46bbcaef3
fix(deps): update all non-major dependencies (#1833)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-27 16:40:12 -05:00
renovate[bot]
4a8fbc675a
chore(deps): lock file maintenance (#1830)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-10 16:06:50 -05:00
renovate[bot]
c9bed44e0e
fix(deps): update all non-major dependencies (#1826)
* fix(deps): update all non-major dependencies

* Format

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-02-10 20:46:53 +00:00
renovate[bot]
750046c4d9
chore(deps): update dependency stylelint-config-standard to v37 (#1824)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-29 20:59:43 +00:00
renovate[bot]
f42403c579
chore(deps): update dependency eslint-config-prettier to v10 (#1822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-01-29 19:57:40 +00:00
renovate[bot]
519ec090c6
chore(deps): lock file maintenance (#1823)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-29 19:46:48 +00:00
renovate[bot]
4e71048997
fix(deps): update all non-major dependencies (#1814)
* fix(deps): update all non-major dependencies

* Dedupe

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-01-29 19:31:18 +00:00
renovate[bot]
5b33056bc5
chore(deps): update dependency webpack-cli to v6 (#1812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-09 15:18:55 +00:00
renovate[bot]
da0051706e
chore(deps): lock file maintenance (#1813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-09 10:11:21 -05:00
renovate[bot]
6ea51af67c
fix(deps): update all non-major dependencies (#1810)
* fix(deps): update all non-major dependencies

* Dedupe

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2025-01-09 14:45:25 +00:00
renovate[bot]
9a46407254
fix(deps): update dependency msw to ^2.7.0 (#1800)
* fix(deps): update dependency msw to ^2.7.0

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-30 13:24:34 -05:00
renovate[bot]
07bd4476b2
chore(deps): update dependency @storybook/addon-webpack5-compiler-swc to v2 (#1807)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-30 17:13:48 +00:00
renovate[bot]
b9993eb5f7
chore(deps): lock file maintenance (#1808)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-30 12:03:27 -05:00
renovate[bot]
5228d46328
fix(deps): update all non-major dependencies (#1794)
* fix(deps): update all non-major dependencies

* Downgrade Ubuntu

Possibly related:

- https://github.com/electron/electron/issues/41066
- https://github.com/SeleniumHQ/selenium/issues/14609

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-30 10:48:57 -05:00
Nathan Bierema
2002a81071 Publish @redux-devtools/rtk-query-monitor 2024-12-16 12:43:15 -05:00
renovate[bot]
c065b03caa
chore(deps): update eslint monorepo to v9 (#1670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-07 00:03:15 +00:00
renovate[bot]
81a9ee33cc
chore(deps): update dependency @types/color to v4 (#1795)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-06 23:45:59 +00:00
renovate[bot]
3c47910110
chore(deps): update dependency @chromatic-com/storybook to v3 (#1787)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-06 23:34:12 +00:00
renovate[bot]
1c6f45fb47
chore(deps): update dependency typescript to ~5.7.2 (#1757)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-06 23:25:49 +00:00
renovate[bot]
054b27a9f8
chore(deps): update dependency @types/node to v22 (#1796)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-06 23:14:52 +00:00
renovate[bot]
415257cd41
fix(deps): update dependency msw to ^2.6.7 (#1763)
* fix(deps): update dependency msw to ^2.6.7

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-06 23:03:53 +00:00
renovate[bot]
14201108e7
chore(deps): lock file maintenance (#1773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-06 22:53:43 +00:00
renovate[bot]
90737b7e26
fix(deps): update all non-major dependencies (#1780)
* fix(deps): update all non-major dependencies

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-12-06 22:39:17 +00:00
Nathan Bierema
54c6f26c81 Publish @redux-devtools/utils
This hasn't been published since the upgrade to Redux 5
2024-12-05 15:57:27 -05:00
takanuva15
6e400f68b3
feat(docs): add reference to new intellij redux devtools plugin (#1788) 2024-11-19 20:57:04 -05:00
renovate[bot]
2c65192b4f
fix(deps): update all non-major dependencies (#1778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 18:54:50 +00:00
renovate[bot]
88a02a8332
chore(deps): update all non-major dependencies (#1764)
* chore(deps): update all non-major dependencies

* Combine @types/lodash

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-10-14 08:51:59 -04:00
github-actions[bot]
04858cd514
Version Packages (#1772)
* Version Packages

* Bump version

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-21 15:31:15 +00:00
Nathan Bierema
b25bf1304b
Send state from background when monitor connects (#1771)
* Send state from background on connection

* Create green-hats-kick.md
2024-09-21 15:17:43 +00:00
Nathan Bierema
41fae27637
Use pnpm for running scripts instead of nx (#1770)
* Use pnpm for running scripts instead of nx

* Fix typos
2024-09-20 03:06:32 +00:00
Nathan Bierema
fdce076757
Enable linting for extension (#1769)
* Enable linting for extension

* Update lock file
2024-09-20 02:51:22 +00:00
github-actions[bot]
b934e80d23
Version Packages (#1768)
* Version Packages

* Update

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-20 01:23:20 +00:00
Nathan Bierema
50d7682776
Fix DevTools from losing connection (#1767)
* Fix DevTools from losing connection

* Create kind-seals-arrive.md
2024-09-20 01:07:52 +00:00
renovate[bot]
344387c9c6
chore(deps): lock file maintenance (#1745)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-16 20:48:34 -04:00
renovate[bot]
80c570d6d0
fix(deps): update dependency msw to ^2.4.7 (#1762)
* fix(deps): update dependency msw to ^2.4.7

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-17 00:19:53 +00:00
renovate[bot]
aca0cd09a1
chore(deps): update dependency @chromatic-com/storybook to v2 (#1756)
* chore(deps): update dependency @chromatic-com/storybook to v2

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-16 23:44:52 +00:00
renovate[bot]
75dbf74963
chore(deps): update all non-major dependencies (#1746)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-16 19:24:11 -04:00
github-actions[bot]
997f7b636d
Version Packages (#1761)
* Version Packages

* Bump

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-16 02:57:02 +00:00
Nathan Bierema
eb3ac09b03
Add logging to background service worker (#1760)
* Add logging in background service worker

* Create ninety-sheep-end.md
2024-09-16 02:19:01 +00:00
renovate[bot]
3c39eb49f2
fix(deps): update dependency msw to ^2.4.4 (#1750)
* fix(deps): update dependency msw to ^2.4.4

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-09 16:49:21 -04:00
github-actions[bot]
61c09e1cc3
Version Packages (#1749)
* Version Packages

* Bump

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-04 02:07:20 +00:00
Nathan Bierema
f1d61580a8
Fix mocking Chrome API for Electron (#1748)
* Fix mocking Chrome API for Electron

* Create chilled-feet-marry.md
2024-09-04 01:47:16 +00:00
renovate[bot]
c5aef77b85
chore(deps): lock file maintenance (#1744)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-01 14:02:40 +00:00
renovate[bot]
908e1c11bd
chore(deps): update pnpm to v9 (#1679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-01 09:41:09 -04:00
renovate[bot]
d591c18fc8
fix(deps): update dependency msw to ^2.4.1 (#1733)
* fix(deps): update dependency msw to ^2.4.1

* Update msw

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-09-01 13:24:59 +00:00
renovate[bot]
bc4b0755c3
chore(deps): lock file maintenance (#1728)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-01 12:57:20 +00:00
renovate[bot]
2c8f0a0544
chore(deps): update dependency @types/node to ^20.16.3 (#1743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-01 12:43:37 +00:00
renovate[bot]
68d4440e38
chore(deps): update all non-major dependencies (#1729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-01 08:30:09 -04:00
Nathan Bierema
c52962d532
Use workspace protocol (#1742) 2024-09-01 04:12:24 +00:00
Nathan Bierema
18b86498e2
Remove workspaces from package.json (#1741) 2024-08-31 22:26:53 -04:00
Nathan Bierema
01ee4e99be
Update pnpm setup GitHub Action (#1740) 2024-08-31 21:55:32 +00:00
github-actions[bot]
c133d59461
Version Packages (#1738)
* Version Packages

* Update

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-08-31 21:23:43 +00:00
Nathan Bierema
fd9f9504f0
Fix monitoring on opening panel (#1739)
* Fix monitoring on opening panel

* Create polite-foxes-rest.md

* Further cleanup

* Fix

* Simplify

* ===
2024-08-31 21:10:34 +00:00
Nathan Bierema
e49708d831
Fix manifest.json for Edge (#1737)
* Fix manifest.json for Edge

* Create unlucky-dots-hammer.md
2024-08-31 13:22:13 +00:00
github-actions[bot]
f64cbda982
Version Packages (#1736)
* Version Packages

* Bump

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-08-31 03:38:12 +00:00
Nathan Bierema
abd03a70c7
Fix: only send data to extension if DevTools are open (#1735)
* Fix: only send data to extension if DevTools are open

* Create odd-apples-argue.md
2024-08-30 23:26:39 -04:00
Nathan Bierema
b3e8f209fd
Remove more unnecessary use of lodash (#1734) 2024-08-30 19:07:05 -04:00
renovate[bot]
238a38fb21
fix(deps): update dependency @rjsf/core to v5 (#1409)
* fix(deps): update dependency @rjsf/core to v5

* redux-devtools-ui

* Update

* Update

* Update

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-08-26 03:16:10 +00:00
renovate[bot]
76183cfa43
chore(deps): lock file maintenance (#1715)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-26 02:11:43 +00:00
renovate[bot]
9fa9a6ff79
fix(deps): update all non-major dependencies (#1713)
* fix(deps): update all non-major dependencies

* weird

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-08-26 01:53:07 +00:00
github-actions[bot]
2a93de46a1
Version Packages (#1720)
* Version Packages

* Bump version numbers

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Bierema <nbierema@gmail.com>
2024-08-17 19:25:57 +00:00
Nathan Bierema
83b2c19a11
Upgrade to Manifest V3 (#1714)
* Update Chrome manifest.json

* Remove use of window in background

* Test devpanel

* Inject pageScript using new API

* Keep connection from devpanel to background alive

* Keep connection from content script to background alive

* Replace page action with action

* Cleanup syncOptions

* Update options to not rely on background page access

* Start work on updating popup

* Updates

* Remove window

* Get opening in a separate window working

* Remove pageScriptWrap

* Add socket to panelStore

* Fix tests

* Try to use MV3 for Firefox

* Fix path

* Fix Chrome E2E tests

* Revert unintentional change

* Skip Electron tests for now

Looks like they're still working through stuff in https://github.com/electron/electron/issues/41613

* Better image centering

The Firefox popup did not like the old CSS. This is still not perfect, but it's better than it was.

* Create shaggy-taxis-cross.md
2024-08-17 19:11:46 +00:00
Nathan Bierema
61ec00f505
Remove unnecessary lodash usage from bundles (#1718)
* Use lodash-es instead of lodash in extension

Produces (slightly) smaller bundles

* Use lodash-es instead of lodash in instrument

* Use lodash-es instead of lodash in utils

* Use lodash-es instead of lodash in redux-devtools

* Remove lodash from instrument

* Remove lodash from redux-devtools

* Remove lodash from utils

* Remove unnecessary mapValues from extension
2024-08-13 23:42:16 -04:00
271 changed files with 17954 additions and 17553 deletions

View File

@ -0,0 +1,5 @@
---
'@redux-devtools/cli': major
---
Require Node.js 20

View File

@ -8,15 +8,12 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: 'ubuntu-22.04'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: nrwl/nx-set-shas@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v6
with:
node-version: 'lts/*'
cache: 'pnpm'

View File

@ -10,18 +10,18 @@ permissions: write-all
jobs:
release:
name: Release
runs-on: ubuntu-latest
runs-on: 'ubuntu-22.04'
steps:
- name: Checkout Repo
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- uses: pnpm/action-setup@v2
- uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 'lts/*'
cache: 'pnpm'
@ -40,19 +40,19 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Archive Chrome Extension
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: chrome
path: extension/chrome/dist
- name: Archive Edge Extension
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: edge
path: extension/edge/dist
- name: Archive Firefox Extension
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: firefox
path: extension/firefox/dist

View File

@ -24,7 +24,7 @@ It can be used as a browser extension (for [Chrome](https://chrome.google.com/we
## Development
This is a monorepo powered by [pnpm](https://pnpm.io/) and [Nx](https://nx.dev/). [Install pnpm](https://pnpm.io/installation) and run `pnpm install` to get started. Each package's dependencies need to be built before the package itself can be built. You can either build all the packages (i.e., `pnpm run build:all`) or use Nx commands to build only the packages necessary for the packages you're working on (i.e., `pnpm nx build remotedev-redux-devtools-extension`).
This is a monorepo powered by [pnpm](https://pnpm.io/). [Install pnpm](https://pnpm.io/installation) and run `pnpm install` to get started. Each package's dependencies need to be built before the package itself can be built. You can either build all the packages (i.e., `pnpm run build:all`) or use pnpm workspace commands to build only the packages necessary for the packages you're working on (i.e., `pnpm --filter "remotedev-redux-devtools-extension" build`).
## Backers

View File

@ -1,4 +1,5 @@
import { defineConfig } from 'eslint/config';
import eslint from '@eslint/js';
import eslintConfigPrettier from 'eslint-config-prettier';
export default [eslint.configs.recommended, eslintConfigPrettier];
export default defineConfig([eslint.configs.recommended, eslintConfigPrettier]);

View File

@ -0,0 +1,41 @@
import { defineConfig } from 'eslint/config';
import eslint from '@eslint/js';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import jest from 'eslint-plugin-jest';
import eslintConfigPrettier from 'eslint-config-prettier';
export default defineConfig([
{
files: ['test/**/*.js', 'test/**/*.jsx'],
...eslint.configs.recommended,
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
...react.configs.flat.recommended,
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
settings: {
react: {
version: 'detect',
},
},
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
...reactHooks.configs.flat.recommended,
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
...jest.configs['flat/recommended'],
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
...jest.configs['jest/style'],
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
...eslintConfigPrettier,
},
]);

View File

@ -1,55 +1,57 @@
import { defineConfig } from 'eslint/config';
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,
export default (tsconfigRootDir, files = ['**/*.ts'], project = true) =>
defineConfig([
{
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',
{
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',
},
},
]);

View File

@ -1,64 +1,66 @@
import { defineConfig } from 'eslint/config';
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,
export default (tsconfigRootDir) =>
defineConfig([
{
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',
{
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',
},
},
]);

View File

@ -1,89 +1,88 @@
import { defineConfig } from 'eslint/config';
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 reactHooks 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,
},
) =>
defineConfig([
{
files,
...eslint.configs.recommended,
},
},
{
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,
},
...tseslint.configs.recommendedTypeChecked.map((config) => ({
files,
...config,
})),
...tseslint.configs.stylisticTypeChecked.map((config) => ({
files,
...config,
})),
{
files,
languageOptions: {
parserOptions: {
project,
tsconfigRootDir,
},
],
'@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',
},
},
},
];
{
files,
...react.configs.flat.recommended,
},
{
files,
settings: {
react: {
version: 'detect',
},
},
},
{
files,
...reactHooks.configs.flat.recommended,
},
{
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',
},
},
]);

View File

@ -1,85 +1,84 @@
import { defineConfig } from 'eslint/config';
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 reactHooks 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,
export default (tsconfigRootDir) =>
defineConfig([
{
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'],
...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'],
...reactHooks.configs.flat.recommended,
},
},
{
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',
{
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',
},
},
]);

View File

@ -1,3 +0,0 @@
node_modules
dist
examples

View File

@ -1,31 +0,0 @@
{
"root": true,
"extends": "eslint-config-airbnb",
"globals": {
"chrome": true,
"__DEVELOPMENT__": true
},
"env": {
"browser": true,
"node": true
},
"rules": {
"react/jsx-uses-react": 2,
"react/jsx-uses-vars": 2,
"react/react-in-jsx-scope": 2,
"react/jsx-quotes": 0,
"block-scoped-var": 0,
"padded-blocks": 0,
"quotes": [1, "single"],
"comma-style": [2, "last"],
"no-use-before-define": [0, "nofunc"],
"func-names": 0,
"prefer-const": 0,
"comma-dangle": 0,
"id-length": 0,
"indent": [2, 2, { "SwitchCase": 1 }],
"new-cap": [2, { "capIsNewExceptions": ["Test"] }],
"default-case": 0
},
"plugins": ["react"]
}

View File

@ -1,5 +1,85 @@
# remotedev-redux-devtools-extension
## 3.2.11
### Patch Changes
- Updated dependencies [6163276]
- @redux-devtools/app@7.0.0
- @redux-devtools/slider-monitor@6.0.0
- @redux-devtools/ui@2.0.0
## 3.2.10
### Patch Changes
- @redux-devtools/app@6.2.2
## 3.2.9
### Patch Changes
- Updated dependencies [91f21b2]
- @redux-devtools/core@4.1.1
- @redux-devtools/slider-monitor@5.1.1
- @redux-devtools/utils@3.1.1
- @redux-devtools/app@6.2.1
## 3.2.8
### Patch Changes
- Updated dependencies [6830118]
- react-json-tree@0.20.0
- @redux-devtools/app@6.2.0
- @redux-devtools/slider-monitor@6.0.0
- @redux-devtools/ui@1.4.0
- @redux-devtools/core@4.1.0
- @redux-devtools/utils@4.0.0
## 3.2.7
### Patch Changes
- b25bf13: Send state from background when monitor connects
## 3.2.6
### Patch Changes
- 50d7682: Fix DevTools from losing connection
## 3.2.5
### Patch Changes
- eb3ac09: Add logging to background service worker
## 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

View File

@ -57,7 +57,7 @@ const composeEnhancers =
compose;
```
> For TypeScript use [`redux-devtools-extension` npm package](#13-use-redux-devtoolsextension-package-from-npm), which contains all the definitions, or just use `(window as any)` (see [Recipes](/docs/Recipes.md#using-in-a-typescript-project) for an example).
> For TypeScript use [`redux-devtools-extension` npm package](#13-use-redux-devtoolsextension-package-from-npm), which contains all the definitions, or just use `(window as any)` (see [Recipes](docs/Recipes.md#using-in-a-typescript-project) for an example).
```js
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
@ -228,7 +228,7 @@ See [integrations](docs/Integrations.md) and [the blog post](https://medium.com/
- [Methods (advanced API)](docs/API/Methods.md)
- [FAQ](docs/FAQ.md)
- Features
- [Trace actions calls](/docs/Features/Trace.md)
- [Trace actions calls](docs/Features/Trace.md)
- [Troubleshooting](docs/Troubleshooting.md)
- [Articles](docs/Articles.md)
- [Videos](docs/Videos.md)

View File

@ -5,7 +5,7 @@ import pug from 'pug';
const args = process.argv.slice(2);
const prod = !args.includes('--dev');
const commonEsbuildOptions = {
await esbuild.build({
bundle: true,
logLevel: 'info',
outdir: 'dist',
@ -15,40 +15,24 @@ const commonEsbuildOptions = {
'process.env.NODE_ENV': prod ? '"production"' : '"development"',
'process.env.BABEL_ENV': prod ? '"production"' : '"development"',
},
};
await esbuild.build({
...commonEsbuildOptions,
entryPoints: [
{ out: 'background.bundle', in: 'src/background/index.ts' },
{ out: 'options.bundle', in: 'src/options/index.tsx' },
{ out: 'window.bundle', in: 'src/window/index.tsx' },
{ out: 'remote.bundle', in: 'src/remote/index.tsx' },
{ out: 'devpanel.bundle', in: 'src/devpanel/index.tsx' },
{ out: 'devtools.bundle', in: 'src/devtools/index.ts' },
{ out: 'content.bundle', in: 'src/contentScript/index.ts' },
{ out: 'page.bundle', in: 'src/pageScript/index.ts' },
...(prod ? [] : [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }]),
],
loader: {
'.woff2': 'file',
},
});
if (prod) {
await esbuild.build({
...commonEsbuildOptions,
entryPoints: [{ out: 'pagewrap.bundle', in: 'src/pageScriptWrap.ts' }],
loader: {
'.js': 'text',
},
});
}
console.log();
console.log('Creating HTML files...');
const htmlFiles = ['devpanel', 'devtools', 'options', 'remote', 'window'];
const htmlFiles = ['devpanel', 'devtools', 'options', 'remote'];
for (const htmlFile of htmlFiles) {
fs.writeFileSync(
`dist/${htmlFile}.html`,

View File

@ -1,28 +1,22 @@
{
"version": "3.1.10",
"version": "3.2.10",
"name": "Redux DevTools",
"description": "Redux DevTools for debugging application's state changes.",
"homepage_url": "https://github.com/reduxjs/redux-devtools",
"manifest_version": 2,
"page_action": {
"manifest_version": 3,
"action": {
"default_icon": "img/logo/gray.png",
"default_title": "Redux DevTools",
"default_popup": "window.html#popup"
"default_popup": "devpanel.html#popup"
},
"commands": {
"devtools-left": {
"description": "DevTools window to left"
},
"devtools-right": {
"description": "DevTools window to right"
},
"devtools-bottom": {
"description": "DevTools window to bottom"
"devtools-window": {
"description": "DevTools window"
},
"devtools-remote": {
"description": "Remote DevTools"
},
"_execute_page_action": {
"_execute_action": {
"suggested_key": {
"default": "Ctrl+Shift+E"
}
@ -34,36 +28,37 @@
"128": "img/logo/128x128.png"
},
"options_ui": {
"page": "options.html",
"chrome_style": true
"page": "options.html"
},
"background": {
"scripts": ["background.bundle.js"],
"persistent": false
"service_worker": "background.bundle.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"exclude_globs": ["https://www.google*"],
"js": ["content.bundle.js", "pagewrap.bundle.js"],
"js": ["content.bundle.js"],
"run_at": "document_start",
"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",
"web_accessible_resources": ["page.bundle.js"],
"externally_connectable": {
"ids": ["*"]
},
"permissions": [
"notifications",
"contextMenus",
"storage",
"file:///*",
"http://*/*",
"https://*/*"
],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;",
"permissions": ["notifications", "contextMenus", "storage"],
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;"
},
"update_url": "https://clients2.google.com/service/update2/crx",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdJEPwY92xUACA9CcDBDBmbdbp8Ap3cKQ0DJTUuVQvqb4FQAv8RtKY3iUjGvdwuAcSJQIZwHXcP2aNDH3TiFik/NhRK2GRW8X3OZyTdkuDueABGP2KEX8q1WQDgjX/rPIinGYztUrvoICw/UerMPwNW62jwGoVU3YhAGf+15CgX2Y6a4tppnf/+1mPedKPidh0RsM+aJY98rX+r1SPAHPcGzMjocLkqcT75DZBXer8VQN14tOOzRCd6T6oy7qm7eWru8lJwcY66qMQvhk0osqEod2G3nA7aTWpmqPFS66VEiecP9PgZlp8gQdgZ3dFhA62exydlD55JuRhiMIR63yQIDAQAB"
}

View File

@ -51,7 +51,6 @@ _number_ - maximum stack trace frames to be stored (in case `trace` option was p
_boolean_ or _object_ which contains:
- **options** `object or boolean`:
- `undefined` - will use regular `JSON.stringify` to send data (it's the fast mode).
- `false` - will handle also circular references.
- `true` - will handle also date, regex, undefined, primitives, error objects, symbols, maps, sets and functions.

View File

@ -1,28 +1,22 @@
{
"version": "3.1.10",
"version": "3.2.10",
"name": "Redux DevTools",
"description": "Redux DevTools for debugging application's state changes.",
"homepage_url": "https://github.com/reduxjs/redux-devtools",
"manifest_version": 2,
"page_action": {
"manifest_version": 3,
"action": {
"default_icon": "img/logo/gray.png",
"default_title": "Redux DevTools",
"default_popup": "window.html#popup"
"default_popup": "devpanel.html#popup"
},
"commands": {
"devtools-left": {
"description": "DevTools window to left"
},
"devtools-right": {
"description": "DevTools window to right"
},
"devtools-bottom": {
"description": "DevTools window to bottom"
"devtools-window": {
"description": "DevTools window"
},
"devtools-remote": {
"description": "Remote DevTools"
},
"_execute_page_action": {
"_execute_action": {
"suggested_key": {
"default": "Ctrl+Shift+E"
}
@ -34,34 +28,35 @@
"128": "img/logo/128x128.png"
},
"options_ui": {
"page": "options.html",
"chrome_style": true
"page": "options.html"
},
"background": {
"scripts": ["background.bundle.js"],
"persistent": false
"service_worker": "background.bundle.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"exclude_globs": ["https://www.google*"],
"js": ["content.bundle.js", "pagewrap.bundle.js"],
"js": ["content.bundle.js"],
"run_at": "document_start",
"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",
"web_accessible_resources": ["page.bundle.js"],
"externally_connectable": {
"ids": ["*"]
},
"permissions": [
"notifications",
"contextMenus",
"storage",
"file:///*",
"http://*/*",
"https://*/*"
],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;"
"permissions": ["notifications", "contextMenus", "storage"],
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; style-src * 'unsafe-inline'; img-src 'self' data:;"
}
}

View File

@ -0,0 +1,38 @@
import globals from 'globals';
import eslintJs from '../eslint.js.config.base.mjs';
import eslintTsReact from '../eslint.ts.react.config.base.mjs';
import eslintJsReactJest from '../eslint.js.react.jest.config.base.mjs';
export default [
...eslintJs,
...eslintTsReact(import.meta.dirname),
...eslintJsReactJest,
{
ignores: [
'chrome',
'dist',
'edge',
'examples',
'firefox',
'test/electron/fixture/dist',
],
},
{
files: ['build.mjs'],
languageOptions: {
globals: {
...globals.nodeBuiltin,
},
},
},
{
files: ['test/**/*.js', 'test/**/*.jsx'],
languageOptions: {
globals: {
...globals.browser,
...globals.node,
EUI: true,
},
},
},
];

View File

@ -1,28 +1,22 @@
{
"version": "3.1.10",
"version": "3.2.10",
"name": "Redux DevTools",
"manifest_version": 2,
"manifest_version": 3,
"description": "Redux Developer Tools for debugging application state changes.",
"homepage_url": "https://github.com/reduxjs/redux-devtools",
"applications": {
"browser_specific_settings": {
"gecko": {
"id": "extension@redux.devtools"
}
},
"page_action": {
"action": {
"default_icon": "img/logo/38x38.png",
"default_title": "Redux DevTools",
"default_popup": "window.html#popup"
"default_popup": "devpanel.html#popup"
},
"commands": {
"devtools-left": {
"description": "DevTools window to left"
},
"devtools-right": {
"description": "DevTools window to right"
},
"devtools-bottom": {
"description": "DevTools window to bottom"
"devtools-window": {
"description": "DevTools window"
},
"devtools-remote": {
"description": "Remote DevTools"
@ -42,21 +36,22 @@
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.bundle.js", "pagewrap.bundle.js"],
"js": ["content.bundle.js"],
"run_at": "document_start",
"all_frames": true
},
{
"matches": ["<all_urls>"],
"js": ["page.bundle.js"],
"run_at": "document_start",
"all_frames": true,
"world": "MAIN"
}
],
"devtools_page": "devtools.html",
"web_accessible_resources": ["page.bundle.js"],
"permissions": [
"notifications",
"contextMenus",
"tabs",
"storage",
"file:///*",
"http://*/*",
"https://*/*"
],
"content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self' data:;"
"permissions": ["notifications", "contextMenus", "tabs", "storage"],
"host_permissions": ["file:///*", "http://*/*", "https://*/*"],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; img-src 'self' data:;"
}
}

View File

@ -3,9 +3,9 @@ module.exports = {
testPathIgnorePatterns: ['<rootDir>/examples'],
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',
'\\.css$': '<rootDir>/test/__mocks__/styleMock.js',
},
transformIgnorePatterns: [
'node_modules/(?!.pnpm|@babel/code-frame|@babel/highlight|@babel/helper-validator-identifier|chalk|d3|dateformat|delaunator|internmap|jsondiffpatch|lodash-es|nanoid|robust-predicates|uuid)',
'node_modules/(?!.pnpm|@babel/code-frame|@babel/highlight|@babel/helper-validator-identifier|@x0k/json-schema-merge|chalk|color|d3|dateformat|delaunator|internmap|jsondiffpatch|js-tokens|lodash-es|nanoid|robust-predicates|uuid)',
],
};

View File

@ -1,7 +1,7 @@
{
"private": true,
"name": "remotedev-redux-devtools-extension",
"version": "3.1.11",
"version": "3.2.11",
"description": "Redux Developer Tools for debugging application state changes.",
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/extension",
"license": "MIT",
@ -16,70 +16,65 @@
"build:examples": "babel-node examples/buildAll.js",
"clean": "rimraf dist && rimraf chrome/dist && rimraf edge/dist && rimraf firefox/dist",
"test:app": "cross-env BABEL_ENV=test jest test/app",
"test:chrome": "jest test/chrome",
"test:chrome": "cross-env SE_FORCE_BROWSER_DOWNLOAD=true jest test/chrome",
"build:test:electron:fixture": "webpack --config test/electron/fixture/webpack.config.js",
"test:electron": "pnpm run build:test:electron:fixture && jest test/electron",
"test": "pnpm run test:app && pnpm run test:chrome && pnpm run test:electron",
"build:test:electron:fixture": "webpack --config test/electron/fixture/webpack.config.js",
"lint": "eslint .",
"type-check": "tsc --noEmit"
},
"dependencies": {
"@emotion/react": "^11.13.0",
"@redux-devtools/app": "^6.1.0",
"@redux-devtools/core": "^4.0.0",
"@redux-devtools/instrument": "^2.1.0",
"@redux-devtools/serialize": "^0.4.1",
"@redux-devtools/slider-monitor": "^5.0.1",
"@redux-devtools/ui": "^1.3.2",
"@redux-devtools/utils": "^3.0.0",
"@reduxjs/toolkit": "^2.2.7",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@redux-devtools/app": "workspace:^",
"@redux-devtools/core": "workspace:^",
"@redux-devtools/instrument": "workspace:^",
"@redux-devtools/serialize": "workspace:^",
"@redux-devtools/slider-monitor": "workspace:^",
"@redux-devtools/ui": "workspace:^",
"@redux-devtools/utils": "workspace:^",
"@reduxjs/toolkit": "^2.11.2",
"@types/jsan": "^3.1.5",
"jsan": "^3.1.14",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-is": "^18.3.1",
"react-json-tree": "^0.19.0",
"react-redux": "^9.1.2",
"lodash-es": "^4.17.22",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-icons": "^5.5.0",
"react-is": "^19.2.3",
"react-json-tree": "workspace:^",
"react-redux": "^9.2.0",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"styled-components": "^5.3.11"
"redux-persist": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@babel/register": "^7.24.6",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
"@types/chrome": "^0.0.269",
"@types/lodash": "^4.17.7",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/styled-components": "^5.1.34",
"@babel/core": "^7.28.6",
"@babel/preset-env": "^7.28.6",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@babel/register": "^7.28.6",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@types/chrome": "^0.1.33",
"@types/lodash-es": "^4.17.12",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"chromedriver": "^126.0.5",
"cross-env": "^7.0.3",
"electron": "^31.3.1",
"esbuild": "^0.23.0",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.9.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"immutable": "^4.3.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"cross-env": "^10.1.0",
"electron": "^31.7.7",
"esbuild": "^0.27.2",
"globals": "^17.0.0",
"immutable": "^5.1.4",
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"pug": "^3.0.3",
"rimraf": "^6.0.1",
"selenium-webdriver": "^4.23.0",
"rimraf": "^6.1.2",
"selenium-webdriver": "^4.39.0",
"sinon-chrome": "^3.0.1",
"ts-jest": "^29.2.4",
"typescript": "~5.5.4",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4"
"ts-jest": "^29.4.6",
"typescript": "~5.9.3",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1"
}
}

View File

@ -18,7 +18,7 @@ import {
TopButtons,
} from '@redux-devtools/app';
import { GoBroadcast } from 'react-icons/go';
import { MdBorderBottom, MdBorderLeft, MdBorderRight } from 'react-icons/md';
import { MdOutlineWindow } from 'react-icons/md';
import type { Position } from '../pageScript/api/openWindow';
import type { SingleMessage } from '../background/store/apiMiddleware';
@ -29,25 +29,21 @@ interface OwnProps {
}
type Props = StateProps & DispatchProps & OwnProps;
declare global {
interface Window {
isElectron?: boolean;
}
}
const isElectron = navigator.userAgent.includes('Electron');
function sendMessage(message: SingleMessage) {
chrome.runtime.sendMessage(message);
async function sendMessage(message: SingleMessage) {
await chrome.runtime.sendMessage(message);
}
class Actions extends Component<Props> {
openWindow = (position: Position) => {
sendMessage({ type: 'OPEN', position });
openWindow = async (position: Position) => {
await sendMessage({ type: 'OPEN', position });
};
openOptionsPage = () => {
if (navigator.userAgent.indexOf('Firefox') !== -1) {
sendMessage({ type: 'OPEN_OPTIONS' });
openOptionsPage = async () => {
if (navigator.userAgent.includes('Firefox')) {
await sendMessage({ type: 'OPEN_OPTIONS' });
} else {
chrome.runtime.openOptionsPage();
await chrome.runtime.openOptionsPage();
}
};
@ -89,7 +85,7 @@ class Actions extends Component<Props> {
{features.import && <ImportButton />}
{position &&
(position !== '#popup' ||
navigator.userAgent.indexOf('Firefox') !== -1) && <PrintButton />}
navigator.userAgent.includes('Firefox')) && <PrintButton />}
<Divider />
<MonitorSelector />
<Divider />
@ -98,37 +94,19 @@ class Actions extends Component<Props> {
<DispatcherButton dispatcherIsOpen={this.props.dispatcherIsOpen} />
)}
<Divider />
{!window.isElectron && position !== '#left' && (
{!isElectron && (
<Button
onClick={() => {
this.openWindow('left');
onClick={async () => {
await this.openWindow('window');
}}
>
<MdBorderLeft />
<MdOutlineWindow />
</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
onClick={() => {
this.openWindow('remote');
onClick={async () => {
await this.openWindow('remote');
}}
>
<GoBroadcast />

View File

@ -27,6 +27,7 @@ class App extends Component<Props> {
<a
href="https://github.com/zalmoxisus/redux-devtools-extension#usage"
target="_blank"
rel="noreferrer"
>
the instructions
</a>

View File

@ -2,34 +2,28 @@ import openDevToolsWindow, { DevToolsPosition } from './openWindow';
export function createMenu() {
const menus = [
{ id: 'devtools-left', title: 'To left' },
{ 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-window', title: 'Open in a window' },
{ id: 'devtools-remote', title: 'Open Remote DevTools' },
];
let shortcuts: { [commandName: string]: string | undefined } = {};
const shortcuts: { [commandName: string]: string | undefined } = {};
chrome.commands.getAll((commands) => {
commands.forEach(({ name, shortcut }) => {
for (const { name, shortcut } of commands) {
shortcuts[name!] = shortcut;
});
}
menus.forEach(({ id, title }) => {
for (const { id, title } of menus) {
chrome.contextMenus.create({
id: id,
title: title + (shortcuts[id] ? ' (' + shortcuts[id] + ')' : ''),
contexts: ['all'],
});
});
}
});
}
export function removeMenu() {
chrome.contextMenus.removeAll();
export async function removeMenu() {
await chrome.contextMenus.removeAll();
}
chrome.contextMenus.onClicked.addListener(({ menuItemId }) => {

View File

@ -1,29 +1,23 @@
import '../chromeApiMock';
import { Store } from 'redux';
import configureStore, { BackgroundAction } from './store/backgroundStore';
import configureStore from './store/backgroundStore';
import openDevToolsWindow, { DevToolsPosition } from './openWindow';
import { createMenu, removeMenu } from './contextMenus';
import syncOptions from '../options/syncOptions';
import { BackgroundState } from './store/backgroundReducer';
declare global {
interface Window {
store: Store<BackgroundState, BackgroundAction>;
}
}
import { getOptions } from '../options/syncOptions';
// Expose the extension's store globally to access it from the windows
// via chrome.runtime.getBackgroundPage
window.store = configureStore();
export const store = configureStore();
// Listen for keyboard shortcuts
chrome.commands.onCommand.addListener((shortcut) => {
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(() => {
syncOptions().get((option) => {
void chrome.action.disable();
getOptions((option) => {
if (option.showContextMenus) createMenu();
});
});
@ -32,6 +26,13 @@ chrome.runtime.onInstalled.addListener(() => {
chrome.storage.onChanged.addListener((changes) => {
if (changes.showContextMenus) {
if (changes.showContextMenus.newValue) createMenu();
else removeMenu();
else void removeMenu();
}
});
// https://developer.chrome.com/docs/extensions/develop/migrate/to-service-workers#keep_a_service_worker_alive_continuously
setInterval(
() =>
void chrome.storage.local.set({ 'last-heartbeat': new Date().getTime() }),
20000,
);

View File

@ -1,11 +1,16 @@
import { LIFTED_ACTION } from '@redux-devtools/app';
import { store } from './index';
export function getReport(
reportId: string,
tabId: string | number,
instanceId: number,
) {
chrome.storage.local.get(['s:hostname', 's:port', 's:secure'], (options) => {
chrome.storage.local.get<{
's:hostname': string | undefined;
's:port': string | undefined;
's:secure': string | undefined;
}>(['s:hostname', 's:port', 's:secure'], (options) => {
if (!options['s:hostname'] || !options['s:port']) return;
const url = `${options['s:secure'] ? 'https' : 'http'}://${
options['s:hostname']
@ -24,7 +29,7 @@ export function getReport(
.then((json) => {
const { payload, preloadedState } = json;
if (!payload) return;
window.store.dispatch({
store.dispatch({
type: LIFTED_ACTION,
message: 'IMPORT',
state: JSON.stringify({ payload, preloadedState }),

View File

@ -1,83 +1,34 @@
export type DevToolsPosition =
| 'devtools-left'
| 'devtools-right'
| 'devtools-bottom'
| 'devtools-panel'
| 'devtools-remote';
export type DevToolsPosition = 'devtools-window' | 'devtools-remote';
let windows: { [K in DevToolsPosition]?: number } = {};
let lastPosition: DevToolsPosition | null = null;
const windows: { [K in DevToolsPosition]?: number } = {};
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]) {
callback();
lastPosition = position;
} else {
let params = { focused: true };
if (lastPosition !== position && position !== 'devtools-panel') {
params = { ...params, ...customOptions };
}
chrome.windows.update(windows[position]!, params, () => {
lastPosition = null;
if (chrome.runtime.lastError) callback();
});
}
}
focusIfExist(() => {
let options: chrome.windows.CreateData = {
type: 'popup',
...customOptions,
};
if (action === 'open') {
options.url = chrome.extension.getURL(
url + '#' + position.substr(position.indexOf('-') + 1),
);
chrome.windows.create(options, (win) => {
windows[position] = win!.id;
if (navigator.userAgent.indexOf('Firefox') !== -1) {
chrome.windows.update(win!.id!, {
focused: true,
...customOptions,
});
}
});
}
if (!windows[position]) {
createWindow(position);
} else {
chrome.windows.update(windows[position], { focused: true }, () => {
if (chrome.runtime.lastError) createWindow(position);
});
}
let params: chrome.windows.CreateData & chrome.windows.UpdateInfo = {
left: 0,
top: 0,
width: 380,
height: window.screen.availHeight,
};
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);
}
function createWindow(position: DevToolsPosition) {
const url = chrome.runtime.getURL(getPath(position));
chrome.windows.create({ type: 'popup', url }, (win) => {
windows[position] = win!.id;
if (navigator.userAgent.includes('Firefox')) {
void chrome.windows.update(win!.id!, { focused: true });
}
});
}
function getPath(position: DevToolsPosition) {
switch (position) {
case 'devtools-window':
return 'devpanel.html';
case 'devtools-remote':
return 'remote.html';
default:
throw new Error('Unrecognized position');
}
}

View File

@ -11,11 +11,7 @@ import {
TOGGLE_PERSIST,
UPDATE_STATE,
} from '@redux-devtools/app';
import syncOptions, {
Options,
OptionsMessage,
SyncOptions,
} from '../../options/syncOptions';
import type { Options, OptionsMessage } from '../../options/syncOptions';
import openDevToolsWindow, { DevToolsPosition } from '../openWindow';
import { getReport } from '../logging';
import { Action, Dispatch, Middleware } from 'redux';
@ -32,6 +28,7 @@ import { LiftedState } from '@redux-devtools/instrument';
import type { BackgroundAction, LiftedActionAction } from './backgroundStore';
import type { Position } from '../../pageScript/api/openWindow';
import type { BackgroundState } from './backgroundReducer';
import { store } from '../index';
interface TabMessageBase {
readonly type: string;
@ -51,6 +48,11 @@ interface StopAction extends TabMessageBase {
readonly id?: never;
}
interface OptionsAction {
readonly type: 'OPTIONS';
readonly options: Options;
}
interface DispatchAction extends TabMessageBase {
readonly type: 'DISPATCH';
readonly action: AppDispatchAction;
@ -159,10 +161,6 @@ export type UpdateStateRequest<S, A extends Action<string>> =
| SerializedActionMessage
| SerializedStateMessage<S, A>;
export interface EmptyUpdateStateAction {
readonly type: typeof UPDATE_STATE;
}
interface UpdateStateAction<S, A extends Action<string>> {
readonly type: typeof UPDATE_STATE;
request: UpdateStateRequest<S, A>;
@ -196,7 +194,7 @@ interface SplitUpdateStateAction<S, A extends Action<string>> {
export type TabMessage =
| StartAction
| StopAction
| OptionsMessage
| OptionsAction
| DispatchAction
| ImportAction
| ActionAction
@ -211,11 +209,6 @@ export type PanelMessage<S, A extends Action<string>> =
export type PanelMessageWithSplitAction<S, A extends Action<string>> =
| PanelMessage<S, A>
| SplitUpdateStateAction<S, A>;
export type MonitorMessage =
| NAAction
| ErrorMessage
| EmptyUpdateStateAction
| SetPersistAction;
type TabPort = Omit<chrome.runtime.Port, 'postMessage'> & {
postMessage: (message: TabMessage) => void;
@ -225,20 +218,15 @@ type PanelPort = Omit<chrome.runtime.Port, 'postMessage'> & {
message: PanelMessageWithSplitAction<S, A>,
) => void;
};
type MonitorPort = Omit<chrome.runtime.Port, 'postMessage'> & {
postMessage: (message: MonitorMessage) => void;
};
export const CONNECTED = 'socket/CONNECTED';
export const DISCONNECTED = 'socket/DISCONNECTED';
const connections: {
readonly tab: { [K in number | string]: TabPort };
readonly panel: { [K in number | string]: PanelPort };
readonly monitor: { [K in number | string]: MonitorPort };
} = {
tab: {},
panel: {},
monitor: {},
};
const chunks: {
[instanceId: string]: PageScriptToContentScriptMessageForwardedToMonitors<
@ -247,7 +235,6 @@ const chunks: {
>;
} = {};
let monitors = 0;
let isMonitored = false;
const getId = (sender: chrome.runtime.MessageSender, name?: string) =>
sender.tab ? sender.tab.id! : name || sender.id!;
@ -261,22 +248,12 @@ type MonitorAction<S, A extends Action<string>> =
// Chrome message limit is 64 MB, but we're using 32 MB to include other object's parts
const maxChromeMsgSize = 32 * 1024 * 1024;
function toMonitors<S, A extends Action<string>>(
action: MonitorAction<S, A>,
tabId?: string | number,
verbose?: boolean,
) {
for (const monitorPort of Object.values(connections.monitor)) {
monitorPort.postMessage(
verbose || action.type === 'ERROR' || action.type === SET_PERSIST
? action
: { type: UPDATE_STATE },
);
}
function toMonitors<S, A extends Action<string>>(action: MonitorAction<S, A>) {
console.log(`Message to monitors: ${action.type}`);
for (const panelPort of Object.values(connections.panel)) {
for (const port of Object.values(connections.panel)) {
try {
panelPort.postMessage(action);
port.postMessage(action);
} catch (err) {
if (
action.type !== UPDATE_STATE ||
@ -307,11 +284,11 @@ function toMonitors<S, A extends Action<string>>(
value;
}
panelPort.postMessage({ ...action, request: splitMessageStart });
port.postMessage({ ...action, request: splitMessageStart });
for (let i = 0; i < toSplit.length; i++) {
for (let j = 0; j < toSplit[i][1].length; j += maxChromeMsgSize) {
panelPort.postMessage({
port.postMessage({
...action,
request: {
split: 'chunk',
@ -324,7 +301,7 @@ function toMonitors<S, A extends Action<string>>(
}
}
panelPort.postMessage({ ...action, request: { split: 'end' } });
port.postMessage({ ...action, request: { split: 'end' } });
}
}
}
@ -340,19 +317,15 @@ interface ImportMessage {
type ToContentScriptMessage = ImportMessage | LiftedActionAction;
function toContentScript(messageBody: ToContentScriptMessage) {
console.log(`Message to tab ${messageBody.id}: ${messageBody.message}`);
if (messageBody.message === 'DISPATCH') {
const { message, action, id, instanceId, state } = messageBody;
connections.tab[id!].postMessage({
type: message,
action,
state: nonReduxDispatch(
window.store,
message,
instanceId,
action as AppDispatchAction,
state,
),
id: instanceId.toString().replace(/^[^\/]+\//, ''),
state: nonReduxDispatch(store, message, instanceId, action, state),
id: instanceId.toString().replace(/^[^/]+\//, ''),
});
} else if (messageBody.message === 'IMPORT') {
const { message, action, id, instanceId, state } = messageBody;
@ -360,13 +333,13 @@ function toContentScript(messageBody: ToContentScriptMessage) {
type: message,
action,
state: nonReduxDispatch(
window.store,
store,
message,
instanceId,
action as unknown as AppDispatchAction,
state,
),
id: instanceId.toString().replace(/^[^\/]+\//, ''),
id: instanceId.toString().replace(/^[^/]+\//, ''),
});
} else if (messageBody.message === 'ACTION') {
const { message, action, id, instanceId, state } = messageBody;
@ -374,13 +347,13 @@ function toContentScript(messageBody: ToContentScriptMessage) {
type: message,
action,
state: nonReduxDispatch(
window.store,
store,
message,
instanceId,
action as unknown as AppDispatchAction,
state,
),
id: instanceId.toString().replace(/^[^\/]+\//, ''),
id: instanceId.toString().replace(/^[^/]+\//, ''),
});
} else if (messageBody.message === 'EXPORT') {
const { message, action, id, instanceId, state } = messageBody;
@ -388,53 +361,41 @@ function toContentScript(messageBody: ToContentScriptMessage) {
type: message,
action,
state: nonReduxDispatch(
window.store,
store,
message,
instanceId,
action as unknown as AppDispatchAction,
state,
),
id: instanceId.toString().replace(/^[^\/]+\//, ''),
id: instanceId.toString().replace(/^[^/]+\//, ''),
});
} else {
const { message, action, id, instanceId, state } = messageBody;
connections.tab[id!].postMessage({
connections.tab[id].postMessage({
type: message,
action,
state: nonReduxDispatch(
window.store,
store,
message,
instanceId,
action as AppDispatchAction,
state,
),
id: (instanceId as number).toString().replace(/^[^\/]+\//, ''),
id: (instanceId as number).toString().replace(/^[^/]+\//, ''),
});
}
}
function toAllTabs(msg: TabMessage) {
const tabs = connections.tab;
Object.keys(tabs).forEach((id) => {
tabs[id].postMessage(msg);
});
}
console.log(`Message to all tabs: ${msg.type}`);
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);
for (const tabPort of Object.values(connections.tab)) {
tabPort.postMessage(msg);
}
isMonitored = shouldMonitor;
}
function getReducerError() {
const instancesState = window.store.getState().instances;
const instancesState = store.getState().instances;
const payload = instancesState.states[instancesState.current];
const computedState = payload.computedStates[payload.currentStateIndex];
if (!computedState) return false;
@ -442,13 +403,13 @@ function getReducerError() {
}
function togglePersist() {
const state = window.store.getState();
const state = store.getState();
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;
window.store.dispatch({ type: REMOVE_INSTANCE, id });
store.dispatch({ type: REMOVE_INSTANCE, id });
toMonitors({ type: 'NA', id });
});
}
}
}
@ -461,45 +422,35 @@ interface OpenOptionsMessage {
readonly type: 'OPEN_OPTIONS';
}
interface GetOptionsMessage {
readonly type: 'GET_OPTIONS';
}
export type SingleMessage =
| OpenMessage
| OpenOptionsMessage
| GetOptionsMessage;
export type SingleMessage = OpenMessage | OpenOptionsMessage | OptionsMessage;
type BackgroundStoreMessage<S, A extends Action<string>> =
| PageScriptToContentScriptMessageWithoutDisconnectOrInitInstance<S, A>
| SplitMessage
| SingleMessage;
type BackgroundStoreResponse = { readonly options: Options };
// Receive messages from content scripts
function messaging<S, A extends Action<string>>(
request: BackgroundStoreMessage<S, A>,
sender: chrome.runtime.MessageSender,
sendResponse?: (response?: BackgroundStoreResponse) => void,
) {
let tabId = getId(sender);
console.log(`Message from tab ${tabId}: ${request.type ?? request.split}`);
if (!tabId) return;
if (sender.frameId) tabId = `${tabId}-${sender.frameId}`;
if (request.type === 'STOP') {
if (!Object.keys(window.store.getState().instances.connections).length) {
window.store.dispatch({ type: DISCONNECTED });
if (!Object.keys(store.getState().instances.connections).length) {
store.dispatch({ type: DISCONNECTED });
}
return;
}
if (request.type === 'OPEN_OPTIONS') {
chrome.runtime.openOptionsPage();
void chrome.runtime.openOptionsPage();
return;
}
if (request.type === 'GET_OPTIONS') {
window.syncOptions.get((options) => {
sendResponse!({ options });
});
if (request.type === 'OPTIONS') {
toAllTabs({ type: 'OPTIONS', options: request.options });
return;
}
if (request.type === 'GET_REPORT') {
@ -507,12 +458,8 @@ function messaging<S, A extends Action<string>>(
return;
}
if (request.type === 'OPEN') {
let position: DevToolsPosition = 'devtools-left';
if (
['remote', 'panel', 'left', 'right', 'bottom'].indexOf(
request.position,
) !== -1
) {
let position: DevToolsPosition = 'devtools-window';
if (['remote', 'window'].includes(request.position)) {
position = ('devtools-' + request.position) as DevToolsPosition;
}
openDevToolsWindow(position);
@ -520,12 +467,12 @@ function messaging<S, A extends Action<string>>(
}
if (request.type === 'ERROR') {
if (request.payload) {
toMonitors(request, tabId);
toMonitors(request);
return;
}
if (!request.message) return;
const reducerError = getReducerError();
chrome.notifications.create('app-error', {
void chrome.notifications.create('app-error', {
type: 'basic',
title: reducerError
? 'An error occurred in the reducer'
@ -560,33 +507,31 @@ function messaging<S, A extends Action<string>>(
if (request.instanceId) {
action.request.instanceId = instanceId;
}
window.store.dispatch(action);
store.dispatch(action);
if (request.type === 'EXPORT') {
toMonitors(action, tabId, true);
} else {
toMonitors(action, tabId);
}
toMonitors(action);
}
function disconnect(
type: 'tab' | 'monitor' | 'panel',
type: 'tab' | 'panel',
id: number | string,
listener?: (message: any, port: chrome.runtime.Port) => void,
listener: (message: any, port: chrome.runtime.Port) => void,
) {
return function disconnectListener() {
console.log(`Disconnected from ${type} ${id}`);
const p = connections[type][id];
if (listener && p) p.onMessage.removeListener(listener);
if (p) p.onDisconnect.removeListener(disconnectListener);
delete connections[type][id];
if (type === 'tab') {
if (!window.store.getState().instances.persisted) {
window.store.dispatch({ type: REMOVE_INSTANCE, id });
if (!store.getState().instances.persisted) {
store.dispatch({ type: REMOVE_INSTANCE, id });
toMonitors({ type: 'NA', id });
}
} else {
monitors--;
if (!monitors) monitorInstances(false);
if (monitors === 0) toAllTabs({ type: 'STOP' });
}
};
}
@ -595,21 +540,23 @@ function onConnect<S, A extends Action<string>>(port: chrome.runtime.Port) {
let id: number | string;
let listener;
window.store.dispatch({ type: CONNECTED, port });
store.dispatch({ type: CONNECTED, port });
if (port.name === 'tab') {
id = getId(port.sender!);
console.log(`Connected to tab ${id}`);
if (port.sender!.frameId) id = `${id}-${port.sender!.frameId}`;
connections.tab[id] = port;
listener = (msg: ContentScriptToBackgroundMessage<S, A>) => {
console.log(`Message from tab ${id}: ${msg.name}`);
if (msg.name === 'INIT_INSTANCE') {
if (typeof id === 'number') {
chrome.pageAction.show(id);
chrome.pageAction.setIcon({ tabId: id, path: 'img/logo/38x38.png' });
void chrome.action.enable(id);
void 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) {
const instanceId = `${id}/${msg.instanceId}`;
const persistedState = state.instances.states[instanceId];
@ -633,22 +580,45 @@ function onConnect<S, A extends Action<string>>(port: chrome.runtime.Port) {
port.onMessage.addListener(listener);
port.onDisconnect.addListener(disconnect('tab', id, listener));
} 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
id = port.name || port.sender!.frameId!;
id = getId(port.sender!, port.name);
console.log(`Connected to monitor ${id}`);
connections.panel[id] = port;
monitorInstances(true, port.name);
monitors++;
toAllTabs({ type: 'START' });
listener = (msg: BackgroundAction) => {
window.store.dispatch(msg);
console.log(`Message from monitor ${id}: ${msg.type}`);
store.dispatch(msg);
};
port.onMessage.addListener(listener);
port.onDisconnect.addListener(disconnect('panel', id, listener));
const { current } = store.getState().instances;
if (current !== 'default') {
const connectionId = Object.entries(
store.getState().instances.connections,
).find(([, instanceIds]) => instanceIds.includes(current))?.[0];
const options = store.getState().instances.options[current];
const state = store.getState().instances.states[current];
const { actionsById, computedStates, committedState, ...rest } = state;
toMonitors({
type: UPDATE_STATE,
request: {
type: 'STATE',
payload: rest as Omit<
LiftedState<S, A, unknown>,
'actionsById' | 'computedStates' | 'committedState'
>,
source: '@devtools-page',
instanceId:
typeof current === 'number' ? current.toString() : current,
actionsById: stringifyJSON(actionsById, options.serialize),
computedStates: stringifyJSON(computedStates, options.serialize),
committedState: typeof committedState !== 'undefined',
},
id: connectionId ?? current,
});
}
}
}
@ -658,18 +628,11 @@ chrome.runtime.onMessage.addListener(messaging);
chrome.runtime.onMessageExternal.addListener(messaging);
chrome.notifications.onClicked.addListener((id) => {
chrome.notifications.clear(id);
openDevToolsWindow('devtools-right');
void chrome.notifications.clear(id);
openDevToolsWindow('devtools-window');
});
declare global {
interface Window {
syncOptions: SyncOptions;
}
}
window.syncOptions = syncOptions(toAllTabs); // Expose to the options page
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
const api: Middleware<{}, BackgroundState, Dispatch<BackgroundAction>> =
(store) => (next) => (untypedAction) => {
const action = untypedAction as BackgroundAction;

View File

@ -1,34 +1,50 @@
// Mock not supported chrome.* API for Firefox and Electron
window.isElectron =
window.navigator && window.navigator.userAgent.indexOf('Electron') !== -1;
const isFirefox = navigator.userAgent.indexOf('Firefox') !== -1;
const isElectron = navigator.userAgent.includes('Electron');
const isFirefox = navigator.userAgent.includes('Firefox');
// Background page only
if (
(window.isElectron &&
location.pathname === '/_generated_background_page.html') ||
(isElectron && location.pathname === '/background.bundle.js') ||
isFirefox
) {
(chrome.runtime as any).onConnectExternal = {
addListener() {},
addListener() {
// do nothing.
},
};
(chrome.runtime as any).onMessageExternal = {
addListener() {},
addListener() {
// do nothing.
},
};
if (window.isElectron) {
if (isElectron) {
(chrome.notifications as any) = {
onClicked: {
addListener() {},
addListener() {
// do nothing.
},
},
create() {
// do nothing.
},
clear() {
// do nothing.
},
create() {},
clear() {},
};
(chrome.contextMenus as any) = {
onClicked: {
addListener() {},
addListener() {
// do nothing.
},
},
};
(chrome.commands as any) = {
onCommand: {
addListener() {
// do nothing.
},
},
};
} else {
@ -39,34 +55,39 @@ if (
}
}
if (window.isElectron) {
if (isElectron) {
if (!chrome.storage.local || !chrome.storage.local.remove) {
(chrome.storage as any).local = {
set(obj: any, callback: any) {
Object.keys(obj).forEach((key) => {
localStorage.setItem(key, obj[key]);
});
set(items: { [key: string]: string }, callback: () => void) {
for (const [key, value] of Object.entries(items)) {
localStorage.setItem(key, value);
}
if (callback) {
callback();
}
},
get(obj: any, callback: any) {
const result: any = {};
Object.keys(obj).forEach((key) => {
result[key] = localStorage.getItem(key) || obj[key];
});
get(
keys: { [key: string]: any },
callback: (items: { [key: string]: any }) => void,
) {
const result = Object.fromEntries(
Object.entries(keys).map(([key, value]) => [
key,
localStorage.getItem(key) ?? value,
]),
);
if (callback) {
callback(result);
}
},
// Electron ~ 1.4.6
remove(items: any, callback: any) {
if (Array.isArray(items)) {
items.forEach((name) => {
localStorage.removeItem(name);
});
remove(keys: string | string[], callback: () => void) {
if (Array.isArray(keys)) {
for (const key of keys) {
localStorage.removeItem(key);
}
} else {
localStorage.removeItem(items);
localStorage.removeItem(keys);
}
if (callback) {
callback();
@ -76,17 +97,17 @@ if (window.isElectron) {
}
// Avoid error: chrome.runtime.sendMessage is not supported responseCallback
const originSendMessage = (chrome.runtime as any).sendMessage;
chrome.runtime.sendMessage = function () {
(chrome.runtime as any).sendMessage = function (...args: unknown[]) {
if (process.env.NODE_ENV === 'development') {
return originSendMessage(...arguments);
return originSendMessage(...args);
}
if (typeof arguments[arguments.length - 1] === 'function') {
Array.prototype.pop.call(arguments);
if (typeof args[arguments.length - 1] === 'function') {
Array.prototype.pop.call(args);
}
return originSendMessage(...arguments);
return originSendMessage(...args);
};
}
if (isFirefox || window.isElectron) {
if (isFirefox || isElectron) {
(chrome.storage as any).sync = chrome.storage.local;
}

View File

@ -1,8 +1,10 @@
import '../chromeApiMock';
import {
injectOptions,
getOptionsFromBg,
getOptions,
isAllowed,
Options,
prefetchOptions,
prepareOptionsForPage,
} from '../options/syncOptions';
import type { TabMessage } from '../background/store/apiMiddleware';
import type {
@ -84,6 +86,13 @@ interface UpdateAction {
readonly source: typeof source;
}
interface OptionsAction {
readonly type: 'OPTIONS';
readonly options: Options;
readonly id: undefined;
readonly source: typeof source;
}
export type ContentScriptToPageScriptMessage =
| StartAction
| StopAction
@ -91,7 +100,8 @@ export type ContentScriptToPageScriptMessage =
| ImportAction
| ActionAction
| ExportAction
| UpdateAction;
| UpdateAction
| OptionsAction;
interface ImportStatePayload<S, A extends Action<string>> {
readonly type: 'IMPORT_STATE';
@ -112,6 +122,7 @@ export type ListenerMessage<S, A extends Action<string>> =
| ActionAction
| ExportAction
| UpdateAction
| OptionsAction
| ImportStateDispatchAction<S, A>;
function postToPageScript(message: ContentScriptToPageScriptMessage) {
@ -156,8 +167,13 @@ function connect() {
source,
});
}
} else if ('options' in message) {
injectOptions(message.options);
} else if (message.type === 'OPTIONS') {
postToPageScript({
type: message.type,
options: prepareOptionsForPage(message.options),
id: undefined,
source,
});
} else {
postToPageScript({
type: message.type,
@ -238,7 +254,7 @@ function tryCatch<S, A extends Action<string>>(
}
newArgs[key as keyof typeof newArgs] = arg;
});
fn(newArgs as any);
fn(newArgs as SplitMessage);
for (let i = 0; i < toSplit.length; i++) {
for (let j = 0; j < toSplit[i][1].length; j += maxChromeMsgSize) {
fn({
@ -289,7 +305,14 @@ function send<S, A extends Action<string>>(
) {
if (!connected) connect();
if (message.type === 'INIT_INSTANCE') {
getOptionsFromBg();
getOptions((options) => {
postToPageScript({
type: 'OPTIONS',
options: prepareOptionsForPage(options),
id: undefined,
source,
});
});
postToBackground({ name: 'INIT_INSTANCE', instanceId: message.instanceId });
} else {
postToBackground({ name: 'RELAY', message });
@ -317,4 +340,6 @@ function handleMessages<S, A extends Action<string>>(
tryCatch(send, message);
}
prefetchOptions();
window.addEventListener('message', handleMessages, false);

View File

@ -5,12 +5,13 @@ html
meta(charset='UTF-8')
title Redux DevTools
include ../style.pug
style.
body {
min-height: 100px;
}
body
#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')
script(src='/devpanel.bundle.js')

View File

@ -6,6 +6,7 @@ import { Persistor } from 'redux-persist';
import {
REMOVE_INSTANCE,
StoreAction,
StoreState,
UPDATE_STATE,
} from '@redux-devtools/app';
import App from '../app/App';
@ -18,24 +19,24 @@ import {
SplitUpdateStateRequest,
UpdateStateRequest,
} from '../background/store/apiMiddleware';
import type { StoreStateWithoutSocket } from './store/panelReducer';
import { PersistGate } from 'redux-persist/integration/react';
const position = location.hash;
const messageStyle: CSSProperties = {
padding: '20px',
paddingTop: '20px',
width: '100%',
textAlign: 'center',
boxSizing: 'border-box',
};
let rendered: boolean | undefined;
let currentRoot: Root | undefined;
let store: Store<StoreStateWithoutSocket, StoreAction> | undefined;
let store: Store<StoreState, StoreAction> | undefined;
let persistor: Persistor | undefined;
let bgConnection: chrome.runtime.Port;
let naTimeout: NodeJS.Timeout;
const isChrome = navigator.userAgent.indexOf('Firefox') === -1;
const isChrome = !navigator.userAgent.includes('Firefox');
function renderNodeAtRoot(node: ReactNode) {
if (currentRoot) currentRoot.unmount();
@ -66,13 +67,19 @@ function renderNA() {
<a
href="https://github.com/zalmoxisus/redux-devtools-extension#usage"
target="_blank"
rel="noreferrer"
>
the instructions
</a>
.
</div>
);
if (isChrome) {
if (
isChrome &&
chrome &&
chrome.devtools &&
chrome.devtools.inspectedWindow
) {
chrome.devtools.inspectedWindow.getResources((resources) => {
if (resources[0].url.substr(0, 4) === 'file') {
message = (
@ -81,6 +88,7 @@ function renderNA() {
<a
href="https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/Troubleshooting.md#access-file-url-file"
target="_blank"
rel="noreferrer"
>
See details
</a>
@ -101,17 +109,22 @@ function renderNA() {
let splitMessage: SplitUpdateStateRequest<unknown, Action<string>>;
function init(id: number) {
function init() {
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 });
bgConnection.onMessage.addListener(
<S, A extends Action<string>>(
message: PanelMessageWithSplitAction<S, A>,
) => {
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 {
if (!rendered) renderDevTools();
@ -128,12 +141,18 @@ function init(id: number) {
}
if (request.split === 'chunk') {
if ((splitMessage as Record<string, unknown>)[request.chunk[0]]) {
(splitMessage as Record<string, unknown>)[request.chunk[0]] +=
request.chunk[1];
if (
(splitMessage as unknown as Record<string, string>)[
request.chunk[0]
]
) {
(splitMessage as unknown as Record<string, string>)[
request.chunk[0]
] += request.chunk[1];
} else {
(splitMessage as Record<string, unknown>)[request.chunk[0]] =
request.chunk[1];
(splitMessage as unknown as Record<string, string>)[
request.chunk[0]
] = request.chunk[1];
}
return;
}
@ -157,4 +176,7 @@ function init(id: number) {
);
}
init(chrome.devtools.inspectedWindow.tabId);
if (position === '#popup') document.body.style.minWidth = '760px';
if (position !== '#popup') document.body.style.minHeight = '100%';
init();

View File

@ -1,45 +1,29 @@
import { combineReducers, Reducer } from 'redux';
import {
connection,
ConnectionState,
instances,
InstancesState,
monitor,
MonitorState,
notification,
NotificationState,
reports,
ReportsState,
section,
SectionState,
StateTreeSettings,
socket,
stateTreeSettings,
StoreAction,
StoreState,
theme,
ThemeState,
} from '@redux-devtools/app';
export interface StoreStateWithoutSocket {
readonly section: SectionState;
readonly theme: ThemeState;
readonly connection: ConnectionState;
readonly monitor: MonitorState;
readonly instances: InstancesState;
readonly reports: ReportsState;
readonly notification: NotificationState;
readonly stateTreeSettings: StateTreeSettings;
}
const rootReducer: Reducer<
StoreStateWithoutSocket,
StoreState,
StoreAction,
Partial<StoreStateWithoutSocket>
Partial<StoreState>
> = combineReducers({
instances,
monitor,
reports,
notification,
section,
socket,
theme,
connection,
stateTreeSettings,

View File

@ -1,9 +1,13 @@
import { createStore, applyMiddleware, Reducer, Store } from 'redux';
import localForage from 'localforage';
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 rootReducer, { StoreStateWithoutSocket } from './panelReducer';
import rootReducer from './panelReducer';
const persistConfig = {
key: 'redux-devtools',
@ -11,8 +15,10 @@ const persistConfig = {
storage: localForage,
};
const persistedReducer: Reducer<StoreStateWithoutSocket, StoreAction> =
persistReducer(persistConfig, rootReducer) as any;
const persistedReducer: Reducer<StoreState, StoreAction> = persistReducer(
persistConfig,
rootReducer,
) as any;
export default function configureStore(
position: string,

View File

@ -7,23 +7,52 @@ import {
TOGGLE_PERSIST,
UPDATE_STATE,
} from '@redux-devtools/app';
import { Dispatch, Middleware } from 'redux';
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
function selectInstance(
tabId: number,
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
next: (action: unknown) => unknown,
) {
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!);
},
);
}
function panelDispatcher(
bgConnection: chrome.runtime.Port,
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
): Middleware<{}, StoreState, Dispatch<StoreAction>> {
let autoselected = false;
const tabId = chrome.devtools.inspectedWindow.tabId;
return (store) => (next) => (untypedAction) => {
const action = untypedAction as StoreAction;
const result = next(action);
if (!autoselected && action.type === UPDATE_STATE && tabId) {
if (!autoselected && action.type === UPDATE_STATE) {
autoselected = true;
const connections = store.getState().instances.connections[tabId];
if (connections && connections.length === 1) {
next({ type: SELECT_INSTANCE, selected: connections[0] });
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) {

View File

@ -1,17 +1,8 @@
function createPanel(url: string) {
chrome.devtools.panels.create(
'Redux',
'img/logo/scalable.png',
url,
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');
}
chrome.devtools.panels.create(
'Redux',
'img/logo/scalable.png',
'devpanel.html',
() => {
// do nothing.
},
);

View File

@ -1,7 +1,7 @@
import React from 'react';
import { OptionsProps } from './Options';
export default ({ options, saveOption }: OptionsProps) => {
export default function AllowToRunGroup({ options, saveOption }: OptionsProps) {
const AllowToRunState = {
EVERYWHERE: true,
ON_SPECIFIC_URLS: false,
@ -50,4 +50,4 @@ export default ({ options, saveOption }: OptionsProps) => {
</div>
</fieldset>
);
};
}

View File

@ -1,7 +1,10 @@
import React from 'react';
import { OptionsProps } from './Options';
export default ({ options, saveOption }: OptionsProps) => {
export default function ContextMenuGroup({
options,
saveOption,
}: OptionsProps) {
return (
<fieldset className="option-group">
<legend className="option-group__title">Context Menu</legend>
@ -23,4 +26,4 @@ export default ({ options, saveOption }: OptionsProps) => {
</div>
</fieldset>
);
};
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import { OptionsProps } from './Options';
export default ({ options, saveOption }: OptionsProps) => {
export default function EditorGroup({ options, saveOption }: OptionsProps) {
const EditorState = {
BROWSER: 0,
EXTERNAL: 1,
@ -21,7 +21,7 @@ export default ({ options, saveOption }: OptionsProps) => {
onChange={() => saveOption('useEditor', EditorState.BROWSER)}
/>
<label className="option__label" htmlFor="editor-browser">
{navigator.userAgent.indexOf('Firefox') !== -1
{navigator.userAgent.includes('Firefox')
? "Don't open in external editor"
: "Use browser's debugger (from browser devpanel only)"}
</label>
@ -80,4 +80,4 @@ export default ({ options, saveOption }: OptionsProps) => {
</div>
</fieldset>
);
};
}

View File

@ -2,7 +2,7 @@ import React from 'react';
import { FilterState } from '../pageScript/api/filters';
import { OptionsProps } from './Options';
export default ({ options, saveOption }: OptionsProps) => {
export default function FilterGroup({ options, saveOption }: OptionsProps) {
return (
<fieldset className="option-group">
<legend className="option-group__title">
@ -68,4 +68,4 @@ export default ({ options, saveOption }: OptionsProps) => {
</div>
</fieldset>
);
};
}

View File

@ -1,7 +1,10 @@
import React from 'react';
import { OptionsProps } from './Options';
export default ({ options, saveOption }: OptionsProps) => {
export default function MiscellaneousGroup({
options,
saveOption,
}: OptionsProps) {
return (
<fieldset className="option-group">
<legend className="option-group__title">Miscellaneous</legend>
@ -47,4 +50,4 @@ export default ({ options, saveOption }: OptionsProps) => {
</div>
</fieldset>
);
};
}

View File

@ -14,34 +14,38 @@ export interface OptionsProps {
) => void;
}
export default (props: OptionsProps) => (
<div>
<EditorGroup {...props} />
<FilterGroup {...props} />
<AllowToRunGroup {...props} />
<MiscellaneousGroup {...props} />
<ContextMenuGroup {...props} />
<div style={{ color: 'red' }}>
<br />
<hr />
Setting options here is discouraged, and will not be possible in the next
major release. Please{' '}
<a
href="https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md"
target="_blank"
style={{ color: 'red' }}
>
specify them as parameters
</a>
. See{' '}
<a
href="https://github.com/zalmoxisus/redux-devtools-extension/issues/296"
target="_blank"
style={{ color: 'red' }}
>
the issue
</a>{' '}
for more details.
export default function OptionsComponent(props: OptionsProps) {
return (
<div>
<EditorGroup {...props} />
<FilterGroup {...props} />
<AllowToRunGroup {...props} />
<MiscellaneousGroup {...props} />
<ContextMenuGroup {...props} />
<div style={{ color: 'red' }}>
<br />
<hr />
Setting options here is discouraged, and will not be possible in the
next major release. Please{' '}
<a
href="https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md"
target="_blank"
rel="noreferrer"
style={{ color: 'red' }}
>
specify them as parameters
</a>
. See{' '}
<a
href="https://github.com/zalmoxisus/redux-devtools-extension/issues/296"
target="_blank"
rel="noreferrer"
style={{ color: 'red' }}
>
the issue
</a>{' '}
for more details.
</div>
</div>
</div>
);
);
}

View File

@ -2,22 +2,25 @@ import '../chromeApiMock';
import React from 'react';
import { createRoot } from 'react-dom/client';
import OptionsComponent from './Options';
import { Options } from './syncOptions';
import {
getOptions,
Options,
OptionsMessage,
saveOption,
subscribeToOptions,
} from './syncOptions';
chrome.runtime.getBackgroundPage((background) => {
const syncOptions = background!.syncOptions;
const saveOption = <K extends keyof Options>(name: K, value: Options[K]) => {
syncOptions.save(name, value);
};
const renderOptions = (options: Options) => {
const root = createRoot(document.getElementById('root')!);
root.render(<OptionsComponent options={options} saveOption={saveOption} />);
};
syncOptions.subscribe(renderOptions);
syncOptions.get((options) => {
renderOptions(options);
});
subscribeToOptions((options) => {
const message: OptionsMessage = { type: 'OPTIONS', options };
void chrome.runtime.sendMessage(message);
});
const renderOptions = (options: Options) => {
const root = createRoot(document.getElementById('root')!);
root.render(<OptionsComponent options={options} saveOption={saveOption} />);
};
subscribeToOptions(renderOptions);
getOptions((options) => {
renderOptions(options);
});

View File

@ -38,21 +38,22 @@ let options: Options | undefined;
let subscribers: ((options: Options) => void)[] = [];
export interface OptionsMessage {
readonly type: 'OPTIONS';
readonly options: Options;
}
type ToAllTabs = (msg: OptionsMessage) => void;
const save =
(toAllTabs: ToAllTabs | undefined) =>
<K extends keyof Options>(key: K, value: Options[K]) => {
let obj: { [K1 in keyof Options]?: Options[K1] } = {};
obj[key] = value;
chrome.storage.sync.set(obj);
options![key] = value;
toAllTabs!({ options: options! });
subscribers.forEach((s) => s(options!));
};
export const saveOption = <K extends keyof Options>(
key: K,
value: Options[K],
) => {
const obj: { [K1 in keyof Options]?: Options[K1] } = {};
obj[key] = value;
void chrome.storage.sync.set(obj);
options![key] = value;
for (const subscriber of subscribers) {
subscriber(options!);
}
};
const migrateOldOptions = (oldOptions: OldOrNewOptions): Options => ({
...oldOptions,
@ -71,10 +72,10 @@ const migrateOldOptions = (oldOptions: OldOrNewOptions): Options => ({
: oldOptions.filter,
});
const get = (callback: (options: Options) => void) => {
export const getOptions = (callback: (options: Options) => void) => {
if (options) callback(options);
else {
chrome.storage.sync.get(
chrome.storage.sync.get<OldOrNewOptions>(
{
useEditor: 0,
editor: '',
@ -91,74 +92,39 @@ const get = (callback: (options: Options) => void) => {
showContextMenus: true,
},
function (items) {
options = migrateOldOptions(items as OldOrNewOptions);
options = migrateOldOptions(items);
callback(options);
},
);
}
};
const subscribe = (callback: (options: Options) => void) => {
export const prefetchOptions = () =>
getOptions(() => {
// do nothing.
});
export const subscribeToOptions = (callback: (options: Options) => void) => {
subscribers = subscribers.concat(callback);
};
const toReg = (str: string) =>
str !== '' ? str.split('\n').filter(Boolean).join('|') : null;
export const injectOptions = (newOptions: Options) => {
if (!newOptions) return;
options = {
...newOptions,
allowlist:
newOptions.filter !== FilterState.DO_NOT_FILTER
? toReg(newOptions.allowlist)!
: newOptions.allowlist,
denylist:
newOptions.filter !== FilterState.DO_NOT_FILTER
? toReg(newOptions.denylist)!
: newOptions.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 prepareOptionsForPage = (options: Options): Options => ({
...options,
allowlist:
options.filter !== FilterState.DO_NOT_FILTER
? toReg(options.allowlist)!
: options.allowlist,
denylist:
options.filter !== FilterState.DO_NOT_FILTER
? toReg(options.denylist)!
: options.denylist,
});
export const isAllowed = (localOptions = options) =>
!localOptions ||
localOptions.inject ||
!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,
};
}

View File

@ -1,4 +1,3 @@
import mapValues from 'lodash/mapValues';
import { Action } from 'redux';
import { LiftedState, PerformAction } from '@redux-devtools/instrument';
import { LocalFilter } from '@redux-devtools/utils';
@ -27,8 +26,7 @@ export function isFiltered<A extends Action<string>>(
) {
if (
noFiltersApplied(localFilter) ||
(typeof action !== 'string' &&
typeof (action.type as string).match !== 'function')
(typeof action !== 'string' && typeof action.type.match !== 'function')
) {
return false;
}
@ -46,10 +44,15 @@ function filterActions<A extends Action<string>>(
actionSanitizer: ((action: A, id: number) => A) | undefined,
): { [p: number]: PerformAction<A> } {
if (!actionSanitizer) return actionsById;
return mapValues(actionsById, (action, id) => ({
...action,
action: actionSanitizer(action.action, id as unknown as number),
}));
return Object.fromEntries(
Object.entries(actionsById).map(([actionId, action]) => [
actionId,
{
...action,
action: actionSanitizer(action.action, actionId as unknown as number),
},
]),
);
}
function filterStates<S>(

View File

@ -58,7 +58,7 @@ export default function importState<S, A extends Action<string>>(
| LiftedState<S, A, unknown> = parse(state) as
| ParsedSerializedLiftedState
| LiftedState<S, A, unknown>;
let preloadedState =
const preloadedState =
'payload' in parsedSerializedLiftedState &&
parsedSerializedLiftedState.preloadedState
? (parse(parsedSerializedLiftedState.preloadedState) as S)

View File

@ -1,5 +1,5 @@
import jsan, { Options } from 'jsan';
import throttle from 'lodash/throttle';
import { throttle } from 'lodash-es';
import { immutableSerialize } from '@redux-devtools/serialize';
import { getActionsArray, getLocalFilter } from '@redux-devtools/utils';
import { isFiltered, PartialLiftedState } from './filters';
@ -222,6 +222,7 @@ function post<S, A extends Action<string>>(
function getStackTrace(
config: Config,
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
toExcludeFromTrace: Function | undefined,
) {
if (!config.trace) return undefined;
@ -248,6 +249,7 @@ function getStackTrace(
typeof Error.stackTraceLimit !== 'number' ||
Error.stackTraceLimit > traceLimit!
) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const frames = stack!.split('\n');
if (frames.length > traceLimit!) {
stack = frames
@ -265,10 +267,11 @@ function amendActionType<A extends Action<string>>(
| StructuralPerformAction<A>[]
| string,
config: Config,
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
toExcludeFromTrace: Function | undefined,
): StructuralPerformAction<A> {
let timestamp = Date.now();
let stack = getStackTrace(config, toExcludeFromTrace);
const timestamp = Date.now();
const stack = getStackTrace(config, toExcludeFromTrace);
if (typeof action === 'string') {
return { action: { type: action } as A, timestamp, stack };
}
@ -595,7 +598,11 @@ export function connect(preConfig: Config): ConnectResponse {
};
const sendDelayed = throttle(() => {
sendMessage(delayedActions, delayedStates as any, config);
sendMessage(
delayedActions,
delayedStates as unknown as LiftedState<unknown, Action<string>, unknown>,
config,
);
delayedActions = [];
delayedStates = [];
}, latency);

View File

@ -10,7 +10,7 @@ function createExpBackoffTimer(step: number) {
return 0;
}
// Calculate next timeout
let timeout = Math.pow(2, count - 1);
const timeout = Math.pow(2, count - 1);
if (count < 5) count += 1;
return timeout * step;
};

View File

@ -1,7 +1,7 @@
import { Action } from 'redux';
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>>(
message: PageScriptToContentScriptMessage<S, A>,
@ -13,6 +13,6 @@ export default function openWindow(position?: Position) {
post({
source: '@devtools-page',
type: 'OPEN',
position: position || 'right',
position: position ?? 'window',
});
}

View File

@ -4,8 +4,8 @@ import { persistState } from '@redux-devtools/core';
import type { ConfigWithExpandedMaxAge } from './index';
export function getUrlParam(key: string) {
const matches = window.location.href.match(
new RegExp(`[?&]${key}=([^&#]+)\\b`),
const matches = new RegExp(`[?&]${key}=([^&#]+)\\b`).exec(
window.location.href,
);
return matches && matches.length > 0 ? matches[1] : null;
}

View File

@ -4,15 +4,8 @@ import {
getActionsArray,
getLocalFilter,
} from '@redux-devtools/utils';
import throttle from 'lodash/throttle';
import {
Action,
ActionCreator,
Dispatch,
Reducer,
StoreEnhancer,
StoreEnhancerStoreCreator,
} from 'redux';
import { throttle } from 'lodash-es';
import { Action, ActionCreator, Dispatch, Reducer, StoreEnhancer } from 'redux';
import Immutable from 'immutable';
import {
EnhancedStore,
@ -60,7 +53,7 @@ type EnhancedStoreWithInitialDispatch<
> = EnhancedStore<S, A, MonitorState> & { initialDispatch: Dispatch<A> };
const source = '@devtools-page';
let stores: {
const stores: {
[K in string | number]: EnhancedStoreWithInitialDispatch<
unknown,
Action<string>,
@ -174,7 +167,7 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
const localFilter = getLocalFilter(config);
const serializeState = getSerializeParameter(config);
const serializeAction = getSerializeParameter(config);
let { stateSanitizer, actionSanitizer, predicate, latency = 500 } = config;
const { stateSanitizer, actionSanitizer, predicate, latency = 500 } = config;
// Deprecate actionsWhitelist and actionsBlacklist
if (config.actionsWhitelist) {
@ -439,6 +432,13 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
serializeAction,
);
}
return;
case 'OPTIONS':
window.devToolsOptions = Object.assign(
window.devToolsOptions || {},
message.options,
);
return;
}
}
@ -447,7 +447,7 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
liftedAction?: LiftedAction<S, A, unknown>,
liftedState?: LiftedState<S, A, unknown> | undefined,
) => {
let m = (config && config.maxAge) || window.devToolsOptions.maxAge || 50;
const m = (config && config.maxAge) || window.devToolsOptions.maxAge || 50;
if (
!liftedAction ||
noFiltersApplied(localFilter) ||
@ -464,10 +464,7 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
if (filteredActionIds.length >= m) {
const stagedActionIds = liftedState!.stagedActionIds;
let i = 1;
while (
maxAge > m &&
filteredActionIds.indexOf(stagedActionIds[i]) === -1
) {
while (maxAge > m && !filteredActionIds.includes(stagedActionIds[i])) {
maxAge--;
i++;
}
@ -539,7 +536,7 @@ function __REDUX_DEVTOOLS_EXTENSION__<S, A extends Action<string>>(
...config,
maxAge: getMaxAge as any,
}) as any
)(reducer_, initialState_) as any;
)(reducer_, initialState_);
if (isInIframe()) setTimeout(init, 3000);
else init();
@ -591,18 +588,18 @@ export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
: never
: {};
: // eslint-disable-next-line @typescript-eslint/no-empty-object-type
{};
const extensionCompose =
(config: Config) =>
<StoreEnhancers extends readonly StoreEnhancer[]>(
...funcs: StoreEnhancers
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {
// @ts-ignore FIXME
// @ts-expect-error FIXME
return (...args) => {
const instanceId = generateId(config.instanceId);
return [preEnhancer(instanceId), ...funcs].reduceRight(
// @ts-ignore FIXME
(composed, f) => f(composed),
__REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args),
);

View File

@ -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);
}

View File

@ -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%';

View File

@ -1,51 +0,0 @@
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
import {
SELECT_INSTANCE,
StoreAction,
StoreState,
UPDATE_STATE,
} from '@redux-devtools/app';
function selectInstance(
tabId: number,
store: MiddlewareAPI<Dispatch<StoreAction>, StoreState>,
next: (action: unknown) => unknown,
) {
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!);
},
);
}
const popupSelector: Middleware<{}, StoreState, Dispatch<StoreAction>> =
(store) => (next) => (untypedAction) => {
const action = untypedAction as 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;
};
export default popupSelector;

View File

@ -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;
}
}

View File

@ -1,32 +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,
Partial<StoreState>
> = combineReducers({
instances,
monitor,
socket,
reports,
notification,
section,
theme,
connection,
stateTreeSettings,
}) as any;
export default rootReducer;

View File

@ -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 as Store, null, () => {
if (store.getState().connection.type !== 'disabled') {
store.dispatch({
type: CONNECT_REQUEST,
});
}
});
return { store, persistor };
}

View File

@ -1,37 +0,0 @@
import {
getActiveInstance,
LIFTED_ACTION,
StoreAction,
StoreState,
TOGGLE_PERSIST,
UPDATE_STATE,
} from '@redux-devtools/app';
import { Dispatch, Middleware, Store } from 'redux';
import type { BackgroundState } from '../../background/store/backgroundReducer';
import type { BackgroundAction } from '../../background/store/backgroundStore';
const syncStores =
(
baseStore: Store<BackgroundState, BackgroundAction>,
): Middleware<{}, StoreState, Dispatch<StoreAction>> =>
(store) =>
(next) =>
(untypedAction) => {
const action = untypedAction as 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;

View File

@ -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')

View File

@ -0,0 +1 @@
module.exports = {};

View File

@ -1 +0,0 @@
export default {};

View File

@ -1,7 +1,7 @@
import React from 'react';
import { render, screen, within } from '@testing-library/react';
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';
Object.defineProperty(window, 'matchMedia', {

View File

@ -20,16 +20,7 @@ describe('API', () => {
expect(message).toEqual({
source: '@devtools-page',
type: 'OPEN',
position: 'right',
});
message = await listenMessage(() => {
window.__REDUX_DEVTOOLS_EXTENSION__.open('left');
});
expect(message).toEqual({
source: '@devtools-page',
type: 'OPEN',
position: 'left',
position: 'window',
});
});

View File

@ -27,9 +27,9 @@ describe('Chrome extension', function () {
});
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();
expect(url).toBe(`chrome-extension://${extensionId}/window.html#left`);
expect(url).toBe(`chrome-extension://${extensionId}/devpanel.html`);
});
it('should match document title', async () => {
@ -37,25 +37,6 @@ describe('Chrome extension', function () {
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 () => {
const url = 'https://zalmoxisus.github.io/examples/router/';
await driver.executeScript(`window.open('${url}')`);
@ -68,6 +49,7 @@ describe('Chrome extension', function () {
await driver.switchTo().window(tabs[0]);
await delay(1000);
const result = await driver.wait(
driver
.findElement(webdriver.By.xpath('//div[@data-testid="actionListRows"]'))
@ -80,4 +62,16 @@ describe('Chrome extension', function () {
);
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) =>
// eslint-disable-next-line jest/expect-expect,jest/valid-title
it(description, () => switchMonitorTests[description](driver)),
);
});

View File

@ -6,7 +6,7 @@ import chromedriver from 'chromedriver';
import { switchMonitorTests, delay } from '../utils/e2e';
const devPanelPath =
'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/window.html';
'chrome-extension://lmhkpmbekcpmknklioeibfkpmmfibljd/devpanel.html';
describe('DevTools panel for Electron', function () {
let driver;
@ -76,6 +76,7 @@ describe('DevTools panel for Electron', function () {
expect(className).not.toMatch(/hidden/); // not hidden
});
// eslint-disable-next-line jest/expect-expect
it('should have Redux DevTools UI on current tab', async () => {
await driver
.switchTo()
@ -107,9 +108,11 @@ describe('DevTools panel for Electron', function () {
});
Object.keys(switchMonitorTests).forEach((description) =>
// eslint-disable-next-line jest/expect-expect,jest/valid-title
it(description, () => switchMonitorTests[description](driver)),
);
// eslint-disable-next-line jest/no-commented-out-tests
/* it('should be no logs in console of main window', async () => {
const handles = await driver.getAllWindowHandles();
await driver.switchTo().window(handles[1]); // Change to main window

40
nx.json
View File

@ -1,40 +0,0 @@
{
"extends": "nx/presets/npm.json",
"npmScope": "undetermined",
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": ["build", "test", "lint", "package", "prepare"]
}
}
},
"targetDependencies": {
"build": [
{
"target": "build",
"projects": "dependencies"
}
],
"prepare": [
{
"target": "prepare",
"projects": "dependencies"
}
],
"package": [
{
"target": "package",
"projects": "dependencies"
}
]
},
"affected": {
"defaultBase": "main"
},
"pluginsConfig": {
"@nrwl/js": {
"analyzeSourceFiles": false
}
}
}

View File

@ -1,43 +1,27 @@
{
"private": true,
"devDependencies": {
"@babel/core": "^7.25.2",
"@changesets/cli": "^2.27.7",
"@eslint/compat": "^1.1.1",
"@eslint/js": "^8.57.0",
"@nrwl/nx-cloud": "^19.0.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jest": "^28.7.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^4.6.2",
"jest": "^29.7.0",
"nx": "^19.5.6",
"prettier": "3.3.3",
"typescript": "~5.5.4",
"typescript-eslint": "^8.0.1"
"@babel/core": "^7.28.6",
"@changesets/cli": "^2.29.8",
"@eslint/js": "^9.39.2",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jest": "^29.12.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"jest": "^30.2.0",
"prettier": "3.8.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.53.0"
},
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check .",
"build:all": "nx run-many --target=build --all --parallel=1",
"lint:all": "nx run-many --target=lint --all --parallel=1",
"test:all": "nx run-many --target=test --all --parallel=1",
"clean:all": "nx run-many --target=clean --all --parallel=1",
"release": "pnpm build:all && changeset publish"
"build:all": "pnpm --recursive run build",
"lint:all": "pnpm --recursive run lint",
"test:all": "pnpm --recursive run test",
"clean:all": "pnpm --recursive run clean",
"release": "pnpm build:all && pnpm publish -r"
},
"workspaces": [
"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.9"
"packageManager": "pnpm@10.28.0"
}

View File

@ -17,7 +17,6 @@
### Major Changes
- b323f77d: Upgrade D3
- Remove UMD build.
- Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.
- The shape of the argument passed to the `onClickText` option has been updated.

View File

@ -25,22 +25,22 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"d3-state-visualizer": "^3.0.0",
"map2tree": "^4.0.0"
"d3-state-visualizer": "workspace:^",
"map2tree": "workspace:^"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-typescript": "^7.24.7",
"@types/node": "^20.14.14",
"babel-loader": "^9.1.3",
"cross-env": "^7.0.3",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"html-webpack-plugin": "^5.6.0",
"@babel/core": "^7.28.6",
"@babel/preset-env": "^7.28.6",
"@babel/preset-typescript": "^7.28.5",
"@types/node": "^24.10.9",
"babel-loader": "^10.0.0",
"cross-env": "^10.1.0",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.5",
"ts-node": "^10.9.2",
"typescript": "~5.5.4",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
"typescript": "~5.9.3",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.3"
}
}

View File

@ -39,14 +39,14 @@
"dependencies": {
"@types/d3": "^7.4.3",
"d3": "^7.9.0",
"d3tooltip": "^4.0.0",
"d3tooltip": "workspace:^",
"deepmerge": "^4.3.1",
"map2tree": "^4.0.0",
"ramda": "^0.30.1"
"map2tree": "workspace:^",
"ramda": "^0.32.0"
},
"devDependencies": {
"@types/ramda": "^0.30.1",
"rimraf": "^6.0.1",
"typescript": "~5.5.4"
"@types/ramda": "^0.31.1",
"rimraf": "^6.1.2",
"typescript": "~5.9.3"
}
}

View File

@ -17,7 +17,6 @@
### Major Changes
- b323f77d: Upgrade D3
- Remove UMD build.
- Upgrade d3 peer dependency from v3 to v7.
- Remove `attr` configuration method.

View File

@ -35,8 +35,8 @@
"devDependencies": {
"@types/d3": "^7.4.3",
"d3": "^7.9.0",
"rimraf": "^6.0.1",
"typescript": "~5.5.4"
"rimraf": "^6.1.2",
"typescript": "~5.9.3"
},
"peerDependencies": {
"@types/d3": "^7.4.3",

View File

@ -37,15 +37,15 @@
"prepublish": "pnpm run lint && pnpm run test"
},
"dependencies": {
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.22"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/jest": "^30.0.0",
"@types/lodash-es": "^4.17.12",
"immutable": "^4.3.7",
"jest": "^29.7.0",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.4",
"typescript": "~5.5.4"
"immutable": "^5.1.4",
"jest": "^30.2.0",
"rimraf": "^6.1.2",
"ts-jest": "^29.4.6",
"typescript": "~5.9.3"
}
}

View File

@ -36,19 +36,19 @@
"prepublish": "pnpm run lint && pnpm run test"
},
"dependencies": {
"@types/lodash": "^4.17.7",
"color": "^4.2.3",
"csstype": "^3.1.3",
"lodash-es": "^4.17.21"
"@types/lodash": "^4.17.23",
"color": "^5.0.3",
"csstype": "^3.2.3",
"lodash-es": "^4.17.22"
},
"devDependencies": {
"@types/color": "^3.0.6",
"@types/jest": "^29.5.12",
"@types/color": "^4.2.0",
"@types/jest": "^30.0.0",
"@types/lodash-es": "^4.17.12",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.4",
"typescript": "~5.5.4"
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"rimraf": "^6.1.2",
"ts-jest": "^29.4.6",
"typescript": "~5.9.3"
}
}

View File

@ -1,5 +1,11 @@
# Change Log
## 0.8.0
### Minor Changes
- 6830118: Add React 19 to peer deps
## 0.7.0
### Minor Changes

View File

@ -1,5 +1,12 @@
# react-dock-demo
## 0.1.7
### Patch Changes
- Updated dependencies [6830118]
- react-dock@0.8.0
## 0.1.6
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"private": true,
"name": "react-dock-demo",
"version": "0.1.6",
"version": "0.1.7",
"license": "MIT",
"scripts": {
"start": "cross-env TS_NODE_PROJECT=\"tsconfig.webpack.json\" webpack serve --open",
@ -10,31 +10,30 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"react": "^18.3.1",
"react-bootstrap": "^2.10.4",
"react-dock": "^0.7.0",
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-is": "^18.3.1",
"styled-components": "^5.3.11"
"@emotion/styled": "^11.14.1",
"react": "^19.2.3",
"react-bootstrap": "^2.10.10",
"react-dock": "workspace:^",
"react-dom": "^19.2.3",
"react-icons": "^5.5.0",
"react-is": "^19.2.3"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@types/node": "^20.14.14",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/styled-components": "^5.1.34",
"babel-loader": "^9.1.3",
"cross-env": "^7.0.3",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"html-webpack-plugin": "^5.6.0",
"@babel/core": "^7.28.6",
"@babel/preset-env": "^7.28.6",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@types/node": "^24.10.9",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"babel-loader": "^10.0.0",
"cross-env": "^10.1.0",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.5",
"ts-node": "^10.9.2",
"typescript": "~5.5.4",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
"typescript": "~5.9.3",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.3"
}
}

View File

@ -2,7 +2,7 @@ import React, { Component } from 'react';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import { BsX } from 'react-icons/bs';
import styled from 'styled-components';
import styled from '@emotion/styled';
import { Dock } from 'react-dock';

View File

@ -1,11 +1,9 @@
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'],
},

View File

@ -1,13 +0,0 @@
module.exports = {
testEnvironment: 'jsdom',
extensionsToTreatAsEsm: ['.ts', '.tsx'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{ tsconfig: 'tsconfig.test.json', useESM: true },
],
},
};

View File

@ -1,6 +1,6 @@
{
"name": "react-dock",
"version": "0.7.0",
"version": "0.8.0",
"description": "Resizable dockable react component",
"keywords": [
"react",
@ -29,30 +29,23 @@
"scripts": {
"build": "tsc",
"clean": "rimraf lib",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
"lint": "eslint .",
"type-check": "tsc --noEmit",
"prepack": "pnpm run clean && pnpm run build",
"prepublish": "pnpm run lint && pnpm run test"
"prepublish": "pnpm run lint"
},
"dependencies": {
"@types/lodash-es": "^4.17.12",
"lodash-es": "^4.17.21"
"lodash-es": "^4.17.22"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/react": "^18.3.3",
"@types/react-test-renderer": "^18.3.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"react": "^18.3.1",
"react-test-renderer": "^18.3.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.4",
"typescript": "~5.5.4"
"@types/react": "^19.2.8",
"react": "^19.2.3",
"rimraf": "^6.1.2",
"typescript": "~5.9.3"
},
"peerDependencies": {
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
"react": "^16.3.0 || ^17.0.0 || ^18.0.0"
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^16.3.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
}

View File

@ -228,12 +228,12 @@ interface Props {
dockHiddenStyle?: React.CSSProperties | null;
duration: number;
children?:
| React.FunctionComponent<{
| ((params: {
position: 'left' | 'right' | 'top' | 'bottom';
isResizing: boolean | undefined;
size: number;
isVisible: boolean | undefined;
}>
}) => ReactNode)
| ReactNode;
}
@ -363,14 +363,7 @@ export default class Dock extends Component<Props, State> {
/>
<div style={styles.dockContent}>
{typeof children === 'function'
? (
children as React.FunctionComponent<{
position: 'left' | 'right' | 'top' | 'bottom';
isResizing: boolean | undefined;
size: number;
isVisible: boolean | undefined;
}>
)({
? children({
position,
isResizing,
size,

View File

@ -39,7 +39,8 @@ const prefixes = ['Moz', 'Webkit', 'ms', 'O'];
function prefixProp<Value>(key: string, value: Value) {
return prefixes.reduce<{ [key: string]: Value }>(
(obj, pre) => (
(obj[pre + key[0].toUpperCase() + key.substr(1)] = value), obj
(obj[pre + key[0].toUpperCase() + key.substr(1)] = value),
obj
),
{},
);

View File

@ -1,23 +0,0 @@
import React from 'react';
import TestRenderer from 'react-test-renderer/shallow';
import Dock from '../src/Dock.js';
describe('Dock component', function () {
it('should have shallow rendering', function () {
const renderer = TestRenderer.createRenderer();
const DockEl = <Dock />;
renderer.render(DockEl);
const result = renderer.getRenderOutput();
expect(DockEl.props).toEqual({
position: 'left',
zIndex: 99999999,
fluid: true,
defaultSize: 0.3,
dimMode: 'opaque',
duration: 200,
});
expect(result.type).toBe('div');
});
});

View File

@ -1,5 +1,11 @@
# Change Log
## 0.20.0
### Minor Changes
- 6830118: Add React 19 to peer deps
## 0.19.0
### Minor Changes
@ -16,7 +22,6 @@
### Major Changes
- 81926f32: Remove UNSAFE method from react-json-tree
- Replace `shouldExpandNode` with `shouldExpandNodeInitially`. This function is now only called when a node in the tree is first rendered, when before it would update the expanded state of the node if the results of calling `shouldExpandNode` changed between renders. There is no way to replicate the old behavior exactly, but the new behavior is the intended behavior for the use cases within Redux DevTools. Please open an issue if you need a way to programatically control the expanded state of nodes.
- Bump the minimum React version from `16.3.0` to `16.8.0` so that `react-json-tree` can use hooks.
- Tightened TypeScript prop types to use `unknown` instead of `any` where possible and make the key path array `readonly`.

View File

@ -1,5 +1,12 @@
# react-json-tree-example
## 1.1.10
### Patch Changes
- Updated dependencies [6830118]
- react-json-tree@0.20.0
## 1.1.9
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"private": true,
"name": "react-json-tree-example",
"version": "1.1.9",
"version": "1.1.10",
"description": "React-Json-Tree example",
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/react-json-tree/examples",
"bugs": {
@ -19,28 +19,28 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"immutable": "^4.3.7",
"react": "^18.3.1",
"react-base16-styling": "^0.10.0",
"react-dom": "^18.3.1",
"react-json-tree": "^0.19.0"
"immutable": "^5.1.4",
"react": "^19.2.3",
"react-base16-styling": "workspace:^",
"react-dom": "^19.2.3",
"react-json-tree": "workspace:^"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@types/node": "^20.14.14",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"babel-loader": "^9.1.3",
"cross-env": "^7.0.3",
"fork-ts-checker-webpack-plugin": "^9.0.2",
"html-webpack-plugin": "^5.6.0",
"@babel/core": "^7.28.6",
"@babel/preset-env": "^7.28.6",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@types/node": "^24.10.9",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"babel-loader": "^10.0.0",
"cross-env": "^10.1.0",
"fork-ts-checker-webpack-plugin": "^9.1.0",
"html-webpack-plugin": "^5.6.5",
"ts-node": "^10.9.2",
"typescript": "~5.5.4",
"webpack": "^5.93.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
"typescript": "~5.9.3",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.3"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "react-json-tree",
"version": "0.19.0",
"version": "0.20.0",
"description": "React JSON Viewer Component, Extracted from redux-devtools",
"keywords": [
"react",
@ -40,22 +40,20 @@
"prepublish": "pnpm run lint && pnpm run test"
},
"dependencies": {
"@types/lodash": "^4.17.7",
"react-base16-styling": "^0.10.0"
"@types/lodash": "^4.17.23",
"react-base16-styling": "workspace:^"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/react": "^18.3.3",
"@types/react-test-renderer": "^18.3.0",
"jest": "^29.7.0",
"react": "^18.3.1",
"react-test-renderer": "^18.3.1",
"rimraf": "^6.0.1",
"ts-jest": "^29.2.4",
"typescript": "~5.5.4"
"@types/jest": "^30.0.0",
"@types/react": "^19.2.8",
"jest": "^30.2.0",
"react": "^19.2.3",
"rimraf": "^6.1.2",
"ts-jest": "^29.4.6",
"typescript": "~5.9.3"
},
"peerDependencies": {
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
}

View File

@ -1,22 +0,0 @@
import React from 'react';
import TestRenderer from 'react-test-renderer/shallow';
import { JSONTree } from '../src/index.js';
import JSONNode from '../src/JSONNode.js';
const BASIC_DATA = { a: 1, b: 'c' };
function render(component: React.ReactElement) {
const renderer = TestRenderer.createRenderer();
renderer.render(component);
return renderer.getRenderOutput();
}
describe('JSONTree', () => {
it('should render basic tree', () => {
const result = render(<JSONTree data={BASIC_DATA} />);
expect(result.type).toBe('ul');
expect(result.props.children.type.name).toBe(JSONNode.name);
});
});

View File

@ -1,5 +1,61 @@
# @redux-devtools/app-core
## 2.0.0
### Major Changes
- 6163276: Replace styled-components with Emotion
### Patch Changes
- Updated dependencies [6163276]
- Updated dependencies [20883e5]
- @redux-devtools/inspector-monitor-test-tab@5.0.0
- @redux-devtools/rtk-query-monitor@6.0.0
- @redux-devtools/slider-monitor@6.0.0
- @redux-devtools/ui@2.0.0
- @redux-devtools/inspector-monitor@6.1.2
## 1.1.2
### Patch Changes
- Updated dependencies [17b55ef]
- @redux-devtools/rtk-query-monitor@5.2.0
## 1.1.1
### Patch Changes
- Updated dependencies [91f21b2]
- @redux-devtools/core@4.1.1
- @redux-devtools/chart-monitor@5.1.1
- @redux-devtools/inspector-monitor@6.1.1
- @redux-devtools/inspector-monitor-test-tab@4.1.1
- @redux-devtools/inspector-monitor-trace-tab@4.1.1
- @redux-devtools/log-monitor@5.1.1
- @redux-devtools/rtk-query-monitor@5.1.1
- @redux-devtools/slider-monitor@5.1.1
## 1.1.0
### Minor Changes
- 6830118: Add React 19 to peer deps
### Patch Changes
- Updated dependencies [6830118]
- @redux-devtools/chart-monitor@6.0.0
- @redux-devtools/inspector-monitor-test-tab@5.0.0
- @redux-devtools/inspector-monitor-trace-tab@5.0.0
- @redux-devtools/inspector-monitor@7.0.0
- @redux-devtools/log-monitor@6.0.0
- @redux-devtools/rtk-query-monitor@6.0.0
- @redux-devtools/slider-monitor@6.0.0
- @redux-devtools/ui@1.4.0
- @redux-devtools/core@4.1.0
## 1.0.0
### Major Changes

View File

@ -10,6 +10,6 @@ module.exports = {
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
},
transformIgnorePatterns: [
'node_modules/(?!.pnpm|@babel/code-frame|@babel/highlight|@babel/helper-validator-identifier|chalk|d3|dateformat|delaunator|internmap|jsondiffpatch|lodash-es|nanoid|robust-predicates|uuid)',
'node_modules/(?!.pnpm|@babel/code-frame|@babel/highlight|@babel/helper-validator-identifier|@x0k/json-schema-merge|chalk|color|d3|dateformat|delaunator|internmap|jsondiffpatch|js-tokens|lodash-es|nanoid|robust-predicates|uuid)',
],
};

View File

@ -1,6 +1,6 @@
{
"name": "@redux-devtools/app-core",
"version": "1.0.0",
"version": "2.0.0",
"description": "Redux DevTools app core",
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-app-core",
"bugs": {
@ -35,69 +35,67 @@
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
},
"dependencies": {
"@babel/runtime": "^7.25.0",
"@redux-devtools/chart-monitor": "^5.0.1",
"@redux-devtools/core": "^4.0.0",
"@redux-devtools/inspector-monitor": "^6.0.0",
"@redux-devtools/inspector-monitor-test-tab": "^4.0.0",
"@redux-devtools/inspector-monitor-trace-tab": "^4.0.0",
"@redux-devtools/log-monitor": "^5.0.0",
"@redux-devtools/rtk-query-monitor": "^5.0.0",
"@redux-devtools/slider-monitor": "^5.0.0",
"@redux-devtools/ui": "^1.3.1",
"d3-state-visualizer": "^3.0.0",
"@babel/runtime": "^7.28.6",
"@redux-devtools/chart-monitor": "workspace:^",
"@redux-devtools/core": "workspace:^",
"@redux-devtools/inspector-monitor": "workspace:^",
"@redux-devtools/inspector-monitor-test-tab": "workspace:^",
"@redux-devtools/inspector-monitor-trace-tab": "workspace:^",
"@redux-devtools/log-monitor": "workspace:^",
"@redux-devtools/rtk-query-monitor": "workspace:^",
"@redux-devtools/slider-monitor": "workspace:^",
"@redux-devtools/ui": "workspace:^",
"d3-state-visualizer": "workspace:^",
"javascript-stringify": "^2.1.0",
"jsan": "^3.1.14",
"jsondiffpatch": "^0.6.0",
"react-icons": "^5.2.1",
"react-is": "^18.3.1"
"jsondiffpatch": "^0.7.3",
"react-icons": "^5.5.0",
"react-is": "^19.2.3"
},
"devDependencies": {
"@babel/cli": "^7.24.8",
"@babel/core": "^7.25.2",
"@babel/eslint-parser": "^7.25.1",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.25.3",
"@babel/preset-react": "^7.24.7",
"@babel/preset-typescript": "^7.24.7",
"@emotion/react": "^11.13.0",
"@reduxjs/toolkit": "^2.2.7",
"@rjsf/core": "^4.2.3",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
"@types/jest": "^29.5.12",
"@babel/cli": "^7.28.6",
"@babel/core": "^7.28.6",
"@babel/eslint-parser": "^7.28.6",
"@babel/plugin-transform-runtime": "^7.28.5",
"@babel/preset-env": "^7.28.6",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@reduxjs/toolkit": "^2.11.2",
"@rjsf/core": "^6.2.4",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@types/jest": "^30.0.0",
"@types/jsan": "^3.1.5",
"@types/json-schema": "^7.0.15",
"@types/node": "^20.14.14",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/styled-components": "^5.1.34",
"cross-env": "^7.0.3",
"esbuild": "^0.23.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"@types/node": "^24.10.9",
"@types/react": "^19.2.8",
"@types/react-dom": "^19.2.3",
"cross-env": "^10.1.0",
"esbuild": "^0.27.2",
"jest": "^30.2.0",
"jest-environment-jsdom": "^30.2.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-redux": "^9.2.0",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"rimraf": "^6.0.1",
"styled-components": "^5.3.11",
"ts-jest": "^29.2.4",
"rimraf": "^6.1.2",
"ts-jest": "^29.4.6",
"ts-node": "^10.9.2",
"typescript": "~5.5.4"
"typescript": "~5.9.3"
},
"peerDependencies": {
"@emotion/react": "^11.13.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@reduxjs/toolkit": "^1.0.0 || ^2.0.0",
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"@types/styled-components": "^5.1.34",
"react": "^16.8.4 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0",
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.4 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-redux": "^8.0.0 || ^9.0.0",
"redux": "^4.0.0 || ^5.0.0",
"redux-persist": "^6.0.0",
"styled-components": "^5.3.11"
"redux-persist": "^6.0.0"
}
}

View File

@ -55,7 +55,7 @@ interface ChangeThemeFormData {
readonly colorPreference: 'auto' | 'light' | 'dark';
}
interface ChangeThemeData {
readonly formData: ChangeThemeFormData;
readonly formData?: ChangeThemeFormData;
}
export interface ChangeThemeAction {
readonly type: typeof CHANGE_THEME;
@ -64,7 +64,7 @@ export interface ChangeThemeAction {
readonly colorPreference: 'auto' | 'light' | 'dark';
}
export function changeTheme(data: ChangeThemeData): ChangeThemeAction {
return { type: CHANGE_THEME, ...data.formData };
return { type: CHANGE_THEME, ...data.formData! };
}
interface ChangeStateTreeSettingsFormData {
@ -73,7 +73,7 @@ interface ChangeStateTreeSettingsFormData {
}
interface ChangeStateTreeSettingsData {
readonly formData: ChangeStateTreeSettingsFormData;
readonly formData?: ChangeStateTreeSettingsFormData;
}
export interface ChangeStateTreeSettingsAction {
@ -85,7 +85,7 @@ export interface ChangeStateTreeSettingsAction {
export function changeStateTreeSettings(
data: ChangeStateTreeSettingsData,
): ChangeStateTreeSettingsAction {
return { type: CHANGE_STATE_TREE_SETTINGS, ...data.formData };
return { type: CHANGE_STATE_TREE_SETTINGS, ...data.formData! };
}
export interface InitMonitorAction {

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react';
import { withTheme } from 'styled-components';
import { withTheme } from '@emotion/react';
import { LiftedAction, LiftedState } from '@redux-devtools/core';
import { Action } from 'redux';
import getMonitor from '../utils/getMonitor';

View File

@ -1,8 +1,14 @@
// Based on https://github.com/YoruNoHikage/redux-devtools-dispatch
import React, { Component } from 'react';
import styled from 'styled-components';
import { Button, Select, Editor, Toolbar } from '@redux-devtools/ui';
import styled from '@emotion/styled';
import {
Button,
Select,
Editor,
Toolbar,
Base16Theme,
} from '@redux-devtools/ui';
import { connect, ResolveThunks } from 'react-redux';
import { dispatchRemotely } from '../../actions';
import { Options } from '../../reducers/instances';
@ -12,7 +18,7 @@ export const DispatcherContainer = styled.div`
flex-direction: column;
flex-shrink: 0;
padding-top: 2px;
background: ${(props) => props.theme.base01};
background: ${(props: { theme?: Base16Theme }) => props.theme!.base01};
`;
export const CodeContainer = styled.div`
@ -24,7 +30,7 @@ export const CodeContainer = styled.div`
export const ActionContainer = styled.div`
display: table;
width: 100%;
color: ${(props) => props.theme.base06};
color: ${(props: { theme?: Base16Theme }) => props.theme!.base06};
> div {
display: table-row;

View File

@ -1,6 +1,6 @@
import React, { Component, RefCallback } from 'react';
import { connect, ResolveThunks } from 'react-redux';
import { withTheme } from 'styled-components';
import { withTheme } from '@emotion/react';
import { tree } from 'd3-state-visualizer';
import type { HierarchyPointNode, Node, Options } from 'd3-state-visualizer';
import { getPath } from '../ChartMonitorWrapper';

View File

@ -1,8 +1,8 @@
import React, { Component } from 'react';
import type { Delta } from 'jsondiffpatch';
import * as htmlFormatter from 'jsondiffpatch/formatters/html';
import styled, { ThemedStyledProps } from 'styled-components';
import { effects, Theme } from '@redux-devtools/ui';
import styled from '@emotion/styled';
import { Base16Theme, effects } from '@redux-devtools/ui';
export const StyledContainer = styled.div`
.jsondiffpatch-delta {
@ -19,8 +19,7 @@ export const StyledContainer = styled.div`
padding: 2px 3px;
border-radius: 3px;
position: relative;
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
color: ${(props: ThemedStyledProps<{}, Theme>) => props.theme.base07};
color: ${(props: { theme?: Base16Theme }) => props.theme!.base07};
display: inline-block;
}
@ -44,25 +43,22 @@ export const StyledContainer = styled.div`
.jsondiffpatch-modified .jsondiffpatch-right-value:before {
vertical-align: top;
padding: 2px;
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
color: ${(props: ThemedStyledProps<{}, Theme>) => props.theme.base0E};
color: ${(props) => props.theme.base0E};
content: ' => ';
}
.jsondiffpatch-added .jsondiffpatch-value pre,
.jsondiffpatch-modified .jsondiffpatch-right-value pre,
.jsondiffpatch-textdiff-added {
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
background: ${(props: ThemedStyledProps<{}, Theme>) =>
effects.color(props.theme.base0B, 'alpha', 0.2)};
background: ${(props: { theme?: Base16Theme }) =>
effects.color(props.theme!.base0B, 'alpha', 0.2)};
}
.jsondiffpatch-deleted pre,
.jsondiffpatch-modified .jsondiffpatch-left-value pre,
.jsondiffpatch-textdiff-deleted {
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
background: ${(props: ThemedStyledProps<{}, Theme>) =>
effects.color(props.theme.base08, 'alpha', 0.2)};
background: ${(props: { theme?: Base16Theme }) =>
effects.color(props.theme!.base08, 'alpha', 0.2)};
text-decoration: line-through;
}
@ -129,14 +125,12 @@ export const StyledContainer = styled.div`
padding: 2px 0;
padding-right: 5px;
vertical-align: top;
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
color: ${(props: ThemedStyledProps<{}, Theme>) => props.theme.base0D};
color: ${(props) => props.theme.base0D};
}
.jsondiffpatch-property-name:after {
content: ': ';
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
color: ${(props: ThemedStyledProps<{}, Theme>) => props.theme.base07};
color: ${(props) => props.theme.base07};
}
.jsondiffpatch-child-node-type-array > .jsondiffpatch-property-name:after {
@ -172,8 +166,7 @@ export const StyledContainer = styled.div`
}
.jsondiffpatch-value pre:after {
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
color: ${(props: ThemedStyledProps<{}, Theme>) => props.theme.base07};
color: ${(props) => props.theme.base07};
content: ',';
}
@ -196,8 +189,7 @@ export const StyledContainer = styled.div`
.jsondiffpatch-moved .jsondiffpatch-moved-destination {
display: inline-block;
${/* eslint-disable-next-line @typescript-eslint/no-empty-object-type */ ''}
background: ${(props: ThemedStyledProps<{}, Theme>) => props.theme.base0A};
background: ${(props) => props.theme.base0A};
}
.jsondiffpatch-moved .jsondiffpatch-moved-destination:before {

View File

@ -1,13 +1,14 @@
import React, { Component } from 'react';
import styled, { withTheme } from 'styled-components';
import styled from '@emotion/styled';
import { withTheme } from '@emotion/react';
import { SliderMonitor } from '@redux-devtools/slider-monitor';
import { LiftedAction } from '@redux-devtools/core';
import { Action } from 'redux';
import { ThemeFromProvider } from '@redux-devtools/ui';
import { Base16Theme, ThemeFromProvider } from '@redux-devtools/ui';
import { State } from '../../reducers/instances';
const SliderWrapper = styled.div`
border-color: ${(props) => props.theme.base02};
border-color: ${(props: { theme?: Base16Theme }) => props.theme!.base02};
border-style: solid;
border-width: 1px 0;
`;

View File

@ -1,5 +1,41 @@
# Change Log
## 7.0.0
### Major Changes
- 6163276: Replace styled-components with Emotion
### Patch Changes
- Updated dependencies [6163276]
- @redux-devtools/app-core@2.0.0
- @redux-devtools/ui@2.0.0
## 6.2.2
### Patch Changes
- @redux-devtools/app-core@1.1.2
## 6.2.1
### Patch Changes
- @redux-devtools/app-core@1.1.1
## 6.2.0
### Minor Changes
- 6830118: Add React 19 to peer deps
### Patch Changes
- Updated dependencies [6830118]
- @redux-devtools/app-core@1.1.0
- @redux-devtools/ui@1.4.0
## 6.1.0
### Minor Changes

Some files were not shown because too many files have changed in this diff Show More