Kaynağa Gözat

Upgrade redux (#2299)

* got rid of redux-thunk

* Bump redux

* Bump ace. Got rid of node-fetch

* Fix vite config
Oleg Shur 2 yıl önce
ebeveyn
işleme
96b00785b5

+ 5 - 9
kafka-ui-react-app/package.json

@@ -10,13 +10,13 @@
     "@fortawesome/fontawesome-free": "^6.1.1",
     "@hookform/error-message": "^2.0.0",
     "@hookform/resolvers": "^2.7.1",
-    "@reduxjs/toolkit": "^1.8.2",
+    "@reduxjs/toolkit": "^1.8.3",
     "@rooks/use-outside-click-ref": "^4.10.1",
     "@testing-library/react": "^13.2.0",
     "@types/testing-library__jest-dom": "^5.14.5",
     "@types/yup": "^0.29.13",
     "@vitejs/plugin-react": "^2.0.0",
-    "ace-builds": "^1.4.12",
+    "ace-builds": "^1.7.1",
     "ajv": "^8.6.3",
     "babel-jest": "^28.1.1",
     "bulma": "^0.9.3",
@@ -27,7 +27,6 @@
     "jest-watch-typeahead": "^2.0.0",
     "json-schema-faker": "^0.5.0-rcv.39",
     "lodash": "^4.17.21",
-    "node-fetch": "^2.6.1",
     "pretty-ms": "7.0.1",
     "react": "^18.1.0",
     "react-ace": "^10.1.0",
@@ -37,10 +36,9 @@
     "react-is": "^18.2.0",
     "react-multi-select-component": "^4.0.6",
     "react-query": "^3.39.1",
-    "react-redux": "^7.2.6",
+    "react-redux": "^8.0.2",
     "react-router-dom": "^6.3.0",
-    "redux": "^4.1.1",
-    "redux-thunk": "^2.3.0",
+    "redux": "^4.2.0",
     "sass": "^1.52.3",
     "styled-components": "^5.3.1",
     "use-debounce": "^8.0.1",
@@ -59,6 +57,7 @@
     "start": "vite",
     "gen:sources": "rimraf src/generated-sources && openapi-generator-cli generate",
     "build": "vite build",
+    "preview": "vite preview",
     "lint": "eslint --ext .tsx,.ts src/",
     "lint:fix": "eslint --ext .tsx,.ts src/ --fix",
     "lint:CI": "eslint --ext .tsx,.ts src/ --max-warnings=0",
@@ -89,9 +88,7 @@
     "@types/react": "^18.0.9",
     "@types/react-datepicker": "^4.4.2",
     "@types/react-dom": "^18.0.3",
-    "@types/react-redux": "^7.1.18",
     "@types/react-router-dom": "^5.3.3",
-    "@types/redux-mock-store": "^1.0.3",
     "@types/styled-components": "^5.1.13",
     "@typescript-eslint/eslint-plugin": "^5.29.0",
     "@typescript-eslint/parser": "^5.29.0",
@@ -116,7 +113,6 @@
     "jest-styled-components": "^7.0.8",
     "lint-staged": "^13.0.2",
     "prettier": "^2.3.1",
-    "redux-mock-store": "^1.5.4",
     "rimraf": "^3.0.2",
     "ts-jest": "^28.0.5",
     "ts-node": "^10.8.1",

+ 61 - 72
kafka-ui-react-app/pnpm-lock.yaml

@@ -12,7 +12,7 @@ specifiers:
   '@hookform/resolvers': ^2.7.1
   '@jest/types': ^28.1.1
   '@openapitools/openapi-generator-cli': ^2.5.1
-  '@reduxjs/toolkit': ^1.8.2
+  '@reduxjs/toolkit': ^1.8.3
   '@rooks/use-outside-click-ref': ^4.10.1
   '@testing-library/dom': ^8.11.1
   '@testing-library/jest-dom': ^5.16.4
@@ -25,16 +25,14 @@ specifiers:
   '@types/react': ^18.0.9
   '@types/react-datepicker': ^4.4.2
   '@types/react-dom': ^18.0.3
-  '@types/react-redux': ^7.1.18
   '@types/react-router-dom': ^5.3.3
-  '@types/redux-mock-store': ^1.0.3
   '@types/styled-components': ^5.1.13
   '@types/testing-library__jest-dom': ^5.14.5
   '@types/yup': ^0.29.13
   '@typescript-eslint/eslint-plugin': ^5.29.0
   '@typescript-eslint/parser': ^5.29.0
   '@vitejs/plugin-react': ^2.0.0
-  ace-builds: ^1.4.12
+  ace-builds: ^1.7.1
   ajv: ^8.6.3
   babel-jest: ^28.1.1
   bulma: ^0.9.3
@@ -65,7 +63,6 @@ specifiers:
   json-schema-faker: ^0.5.0-rcv.39
   lint-staged: ^13.0.2
   lodash: ^4.17.21
-  node-fetch: ^2.6.1
   prettier: ^2.3.1
   pretty-ms: 7.0.1
   react: ^18.1.0
@@ -76,11 +73,9 @@ specifiers:
   react-is: ^18.2.0
   react-multi-select-component: ^4.0.6
   react-query: ^3.39.1
-  react-redux: ^7.2.6
+  react-redux: ^8.0.2
   react-router-dom: ^6.3.0
-  redux: ^4.1.1
-  redux-mock-store: ^1.5.4
-  redux-thunk: ^2.3.0
+  redux: ^4.2.0
   rimraf: ^3.0.2
   sass: ^1.52.3
   styled-components: ^5.3.1
@@ -101,24 +96,23 @@ dependencies:
   '@fortawesome/fontawesome-free': 6.1.1
   '@hookform/error-message': 2.0.0_l2dcsysovzdujulgxvsen7vbsm
   '@hookform/resolvers': 2.8.9_react-hook-form@7.6.9
-  '@reduxjs/toolkit': 1.8.2_ydj23m2apjohmawqetv7uxfa2i
+  '@reduxjs/toolkit': 1.8.3_ctm756ikdwcjcvyfxxwskzbr6q
   '@rooks/use-outside-click-ref': 4.11.2_react@18.1.0
   '@testing-library/react': 13.2.0_ef5jwxihqo6n7gxfmzogljlgcm
   '@types/testing-library__jest-dom': 5.14.5
   '@types/yup': 0.29.13
   '@vitejs/plugin-react': 2.0.0_vite@3.0.2
-  ace-builds: 1.4.13
+  ace-builds: 1.7.1
   ajv: 8.8.2
   babel-jest: 28.1.1_@babel+core@7.18.2
   bulma: 0.9.3
   classnames: 2.3.1
   dayjs: 1.11.3
-  fetch-mock: 9.11.0_node-fetch@2.6.7
+  fetch-mock: 9.11.0
   jest: 28.1.1_yqiaopbgmqcuvx27p5xxvum6wm
   jest-watch-typeahead: 2.0.0_jest@28.1.1
   json-schema-faker: 0.5.0-rcv.40
   lodash: 4.17.21
-  node-fetch: 2.6.7
   pretty-ms: 7.0.1
   react: 18.1.0
   react-ace: 10.1.0_ef5jwxihqo6n7gxfmzogljlgcm
@@ -128,10 +122,9 @@ dependencies:
   react-is: 18.2.0
   react-multi-select-component: 4.0.6_react@18.1.0
   react-query: 3.39.1_ef5jwxihqo6n7gxfmzogljlgcm
-  react-redux: 7.2.6_ef5jwxihqo6n7gxfmzogljlgcm
+  react-redux: 8.0.2_nfqigfgwurfoimtkde74cji6ga
   react-router-dom: 6.3.0_ef5jwxihqo6n7gxfmzogljlgcm
-  redux: 4.1.2
-  redux-thunk: 2.4.1_redux@4.1.2
+  redux: 4.2.0
   sass: 1.52.3
   styled-components: 5.3.1_uuaz5p7xzfmtjacf6iqf7idnby
   use-debounce: 8.0.1_react@18.1.0
@@ -156,9 +149,7 @@ devDependencies:
   '@types/react': 18.0.9
   '@types/react-datepicker': 4.4.2_react@18.1.0
   '@types/react-dom': 18.0.5
-  '@types/react-redux': 7.1.24
   '@types/react-router-dom': 5.3.3
-  '@types/redux-mock-store': 1.0.3
   '@types/styled-components': 5.1.18
   '@typescript-eslint/eslint-plugin': 5.29.0_uaxwak76nssfibsnotx5epygnu
   '@typescript-eslint/parser': 5.29.0_vjep2yp2sits3sqnodefgcbnfi
@@ -176,14 +167,13 @@ devDependencies:
   eslint-plugin-prettier: 4.0.0_q7a4ir2sdihdzpzdlnbgmzjlpq
   eslint-plugin-react: 7.29.4_eslint@8.16.0
   eslint-plugin-react-hooks: 4.5.0_eslint@8.16.0
-  fetch-mock-jest: 1.5.1_node-fetch@2.6.7
+  fetch-mock-jest: 1.5.1
   husky: 8.0.1
   jest-environment-jsdom: 28.1.1
   jest-sonar-reporter: 2.0.0
   jest-styled-components: 7.0.8_styled-components@5.3.1
   lint-staged: 13.0.2
   prettier: 2.5.1
-  redux-mock-store: 1.5.4
   rimraf: 3.0.2
   ts-jest: 28.0.5_c4h4g76dcvkfgjwf6rprlfxfli
   ts-node: 10.8.1_t4lrjbt3sxauai4t5o275zsepa
@@ -2343,11 +2333,11 @@ packages:
   /@popperjs/core/2.9.2:
     resolution: {integrity: sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==}
 
-  /@reduxjs/toolkit/1.8.2_ydj23m2apjohmawqetv7uxfa2i:
-    resolution: {integrity: sha512-CtPw5TkN1pHRigMFCOS/0qg3b/yfPV5qGCsltVnIz7bx4PKTJlGHYfIxm97qskLknMzuGfjExaYdXJ77QTL0vg==}
+  /@reduxjs/toolkit/1.8.3_ctm756ikdwcjcvyfxxwskzbr6q:
+    resolution: {integrity: sha512-lU/LDIfORmjBbyDLaqFN2JB9YmAT1BElET9y0ZszwhSBa5Ef3t6o5CrHupw5J1iOXwd+o92QfQZ8OJpwXvsssg==}
     peerDependencies:
       react: ^16.9.0 || ^17.0.0 || ^18
-      react-redux: ^7.2.1 || ^8.0.0-beta
+      react-redux: ^7.2.1 || ^8.0.2
     peerDependenciesMeta:
       react:
         optional: true
@@ -2356,9 +2346,9 @@ packages:
     dependencies:
       immer: 9.0.12
       react: 18.1.0
-      react-redux: 7.2.6_ef5jwxihqo6n7gxfmzogljlgcm
-      redux: 4.1.2
-      redux-thunk: 2.4.1_redux@4.1.2
+      react-redux: 8.0.2_nfqigfgwurfoimtkde74cji6ga
+      redux: 4.2.0
+      redux-thunk: 2.4.1_redux@4.2.0
       reselect: 4.1.5
     dev: false
 
@@ -2583,14 +2573,6 @@ packages:
     dependencies:
       '@types/react': 18.0.9
 
-  /@types/react-redux/7.1.24:
-    resolution: {integrity: sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==}
-    dependencies:
-      '@types/hoist-non-react-statics': 3.3.1
-      '@types/react': 18.0.9
-      hoist-non-react-statics: 3.3.2
-      redux: 4.1.2
-
   /@types/react-router-dom/5.3.3:
     resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==}
     dependencies:
@@ -2613,12 +2595,6 @@ packages:
       '@types/scheduler': 0.16.2
       csstype: 3.0.8
 
-  /@types/redux-mock-store/1.0.3:
-    resolution: {integrity: sha512-Wqe3tJa6x9MxMN4DJnMfZoBRBRak1XTPklqj4qkVm5VBpZnC8PSADf4kLuFQ9NAdHaowfWoEeUMz7NWc2GMtnA==}
-    dependencies:
-      redux: 4.1.2
-    dev: true
-
   /@types/scheduler/0.16.2:
     resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
 
@@ -2642,6 +2618,10 @@ packages:
     resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==}
     dev: true
 
+  /@types/use-sync-external-store/0.0.3:
+    resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==}
+    dev: false
+
   /@types/yargs-parser/20.2.0:
     resolution: {integrity: sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==}
 
@@ -2875,10 +2855,6 @@ packages:
     resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
     dev: true
 
-  /ace-builds/1.4.13:
-    resolution: {integrity: sha512-SOLzdaQkY6ecPKYRDDg+MY1WoGgXA34cIvYJNNoBMGGUswHmlauU2Hy0UL96vW0Fs/LgFbMUjD+6vqzWTldIYQ==}
-    dev: false
-
   /ace-builds/1.7.1:
     resolution: {integrity: sha512-1mcbP5kXvr729sJ9dA/8tul0pjuvKbma0LF/ZMRwPEwjoNWNpe/x0OXpaPJo36aRpZCjRZMl5zsME3hAKTiaNw==}
     dev: false
@@ -4730,7 +4706,7 @@ packages:
     dependencies:
       bser: 2.1.1
 
-  /fetch-mock-jest/1.5.1_node-fetch@2.6.7:
+  /fetch-mock-jest/1.5.1:
     resolution: {integrity: sha512-+utwzP8C+Pax1GSka3nFXILWMY3Er2L+s090FOgqVNrNCPp0fDqgXnAHAJf12PLHi0z4PhcTaZNTz8e7K3fjqQ==}
     engines: {node: '>=8.0.0'}
     peerDependencies:
@@ -4739,13 +4715,12 @@ packages:
       node-fetch:
         optional: true
     dependencies:
-      fetch-mock: 9.11.0_node-fetch@2.6.7
-      node-fetch: 2.6.7
+      fetch-mock: 9.11.0
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /fetch-mock/9.11.0_node-fetch@2.6.7:
+  /fetch-mock/9.11.0:
     resolution: {integrity: sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q==}
     engines: {node: '>=4.0.0'}
     peerDependencies:
@@ -4761,7 +4736,6 @@ packages:
       glob-to-regexp: 0.4.1
       is-subset: 0.1.1
       lodash.isequal: 4.5.0
-      node-fetch: 2.6.7
       path-to-regexp: 2.4.0
       querystring: 0.2.1
       whatwg-url: 6.5.0
@@ -6063,10 +6037,6 @@ packages:
   /lodash.isequal/4.5.0:
     resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
 
-  /lodash.isplainobject/4.0.6:
-    resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
-    dev: true
-
   /lodash.memoize/4.1.2:
     resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
     dev: true
@@ -6246,6 +6216,7 @@ packages:
         optional: true
     dependencies:
       whatwg-url: 5.0.0
+    dev: true
 
   /node-int64/0.4.0:
     resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
@@ -6750,26 +6721,38 @@ packages:
       react-dom: 18.1.0_react@18.1.0
     dev: false
 
-  /react-redux/7.2.6_ef5jwxihqo6n7gxfmzogljlgcm:
-    resolution: {integrity: sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==}
+  /react-redux/8.0.2_nfqigfgwurfoimtkde74cji6ga:
+    resolution: {integrity: sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA==}
     peerDependencies:
-      react: ^16.8.3 || ^17
-      react-dom: '*'
-      react-native: '*'
+      '@types/react': ^16.8 || ^17.0 || ^18.0
+      '@types/react-dom': ^16.8 || ^17.0 || ^18.0
+      react: ^16.8 || ^17.0 || ^18.0
+      react-dom: ^16.8 || ^17.0 || ^18.0
+      react-native: '>=0.59'
+      redux: ^4
     peerDependenciesMeta:
+      '@types/react':
+        optional: true
+      '@types/react-dom':
+        optional: true
       react-dom:
         optional: true
       react-native:
         optional: true
+      redux:
+        optional: true
     dependencies:
       '@babel/runtime': 7.17.9
-      '@types/react-redux': 7.1.24
+      '@types/hoist-non-react-statics': 3.3.1
+      '@types/react': 18.0.9
+      '@types/react-dom': 18.0.5
+      '@types/use-sync-external-store': 0.0.3
       hoist-non-react-statics: 3.3.2
-      loose-envify: 1.4.0
-      prop-types: 15.8.1
       react: 18.1.0
       react-dom: 18.1.0_react@18.1.0
-      react-is: 17.0.2
+      react-is: 18.2.0
+      redux: 4.2.0
+      use-sync-external-store: 1.2.0_react@18.1.0
     dev: false
 
   /react-refresh/0.14.0:
@@ -6837,24 +6820,19 @@ packages:
       strip-indent: 3.0.0
     dev: true
 
-  /redux-mock-store/1.5.4:
-    resolution: {integrity: sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==}
-    dependencies:
-      lodash.isplainobject: 4.0.6
-    dev: true
-
-  /redux-thunk/2.4.1_redux@4.1.2:
+  /redux-thunk/2.4.1_redux@4.2.0:
     resolution: {integrity: sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==}
     peerDependencies:
       redux: ^4
     dependencies:
-      redux: 4.1.2
+      redux: 4.2.0
     dev: false
 
-  /redux/4.1.2:
-    resolution: {integrity: sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==}
+  /redux/4.2.0:
+    resolution: {integrity: sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==}
     dependencies:
       '@babel/runtime': 7.17.9
+    dev: false
 
   /reflect-metadata/0.1.13:
     resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==}
@@ -7439,6 +7417,7 @@ packages:
 
   /tr46/0.0.3:
     resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+    dev: true
 
   /tr46/1.0.1:
     resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
@@ -7685,6 +7664,14 @@ packages:
       react: 18.1.0
     dev: false
 
+  /use-sync-external-store/1.2.0_react@18.1.0:
+    resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+    peerDependencies:
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+    dependencies:
+      react: 18.1.0
+    dev: false
+
   /util-deprecate/1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
     dev: true
@@ -7782,6 +7769,7 @@ packages:
 
   /webidl-conversions/3.0.1:
     resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+    dev: true
 
   /webidl-conversions/4.0.2:
     resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
@@ -7828,6 +7816,7 @@ packages:
     dependencies:
       tr46: 0.0.3
       webidl-conversions: 3.0.1
+    dev: true
 
   /whatwg-url/6.5.0:
     resolution: {integrity: sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==}

+ 3 - 3
kafka-ui-react-app/src/components/KsqlDb/List/List.tsx

@@ -1,7 +1,6 @@
 import React, { FC } from 'react';
 import useAppParams from 'lib/hooks/useAppParams';
 import * as Metrics from 'components/common/Metrics';
-import { useSelector, useDispatch } from 'react-redux';
 import { getKsqlDbTables } from 'redux/reducers/ksqlDb/selectors';
 import {
   clusterKsqlDbQueryRelativePath,
@@ -16,15 +15,16 @@ import { Button } from 'components/common/Button/Button';
 import Navbar from 'components/common/Navigation/Navbar.styled';
 import { NavLink, Route, Routes, Navigate } from 'react-router-dom';
 import { fetchKsqlDbTables } from 'redux/reducers/ksqlDb/ksqlDbSlice';
+import { useAppDispatch, useAppSelector } from 'lib/hooks/redux';
 
 import KsqlDbItem, { KsqlDbItemType } from './KsqlDbItem/KsqlDbItem';
 
 const List: FC = () => {
   const { clusterName } = useAppParams<ClusterNameRoute>();
-  const dispatch = useDispatch();
+  const dispatch = useAppDispatch();
 
   const { rows, fetching, tablesCount, streamsCount } =
-    useSelector(getKsqlDbTables);
+    useAppSelector(getKsqlDbTables);
 
   React.useEffect(() => {
     dispatch(fetchKsqlDbTables(clusterName));

+ 3 - 3
kafka-ui-react-app/src/components/KsqlDb/Query/Query.tsx

@@ -5,13 +5,13 @@ import {
   executeKsql,
   resetExecutionResult,
 } from 'redux/reducers/ksqlDb/ksqlDbSlice';
-import { useDispatch, useSelector } from 'react-redux';
 import { getKsqlExecution } from 'redux/reducers/ksqlDb/selectors';
 import { BASE_PARAMS } from 'lib/constants';
 import { KsqlResponse, KsqlTableResponse } from 'generated-sources';
 import { alertAdded, alertDissmissed } from 'redux/reducers/alerts/alertsSlice';
 import now from 'lodash/now';
 import { ClusterNameRoute } from 'lib/paths';
+import { useAppDispatch, useAppSelector } from 'lib/hooks/redux';
 
 import type { FormValues } from './QueryForm/QueryForm';
 import * as S from './Query.styled';
@@ -69,9 +69,9 @@ const Query: FC = () => {
     isOpen: false,
   });
   const [fetching, setFetching] = useState(false);
-  const dispatch = useDispatch();
+  const dispatch = useAppDispatch();
 
-  const { executionResult } = useSelector(getKsqlExecution);
+  const { executionResult } = useAppSelector(getKsqlExecution);
   const [KSQLTable, setKSQLTable] = useState<KsqlTableResponse | null>(null);
 
   const reset = useCallback(() => {

+ 17 - 44
kafka-ui-react-app/src/components/Topics/New/__test__/New.spec.tsx

@@ -1,9 +1,6 @@
 import React from 'react';
 import New from 'components/Topics/New/New';
 import { Route, Routes } from 'react-router-dom';
-import configureStore from 'redux-mock-store';
-import { RootState } from 'redux/interfaces';
-import * as redux from 'react-redux';
 import { act, screen, waitFor } from '@testing-library/react';
 import {
   clusterTopicCopyPath,
@@ -12,44 +9,26 @@ import {
 } from 'lib/paths';
 import userEvent from '@testing-library/user-event';
 import { render } from 'lib/testHelpers';
-
-const { Provider } = redux;
-
-const mockStore = configureStore();
+import { useAppDispatch } from 'lib/hooks/redux';
 
 const clusterName = 'local';
 const topicName = 'test-topic';
 
-const initialState: Partial<RootState> = {};
-const storeMock = mockStore(initialState);
-
 const mockNavigate = jest.fn();
 jest.mock('react-router-dom', () => ({
   ...jest.requireActual('react-router-dom'),
   useNavigate: () => mockNavigate,
 }));
+jest.mock('lib/hooks/redux', () => ({
+  ...jest.requireActual('lib/hooks/redux'),
+  useAppDispatch: jest.fn(),
+}));
 
-const renderComponent = (path: string, store = storeMock) => {
+const renderComponent = (path: string) => {
   render(
     <Routes>
-      <Route
-        path={clusterTopicNewPath()}
-        element={
-          <Provider store={store}>
-            <New />
-          </Provider>
-        }
-      />
-
-      <Route
-        path={clusterTopicCopyPath()}
-        element={
-          <Provider store={store}>
-            <New />
-          </Provider>
-        }
-      />
-
+      <Route path={clusterTopicNewPath()} element={<New />} />
+      <Route path={clusterTopicCopyPath()} element={<New />} />
       <Route path={clusterTopicPath()} element="New topic path" />
     </Routes>,
     { initialEntries: [path] }
@@ -93,34 +72,29 @@ describe('New', () => {
   });
 
   it('submits valid form', async () => {
-    const useDispatchSpy = jest.spyOn(redux, 'useDispatch');
     const useDispatchMock = jest.fn(() => ({
       meta: { requestStatus: 'fulfilled' },
-    })) as jest.Mock;
-    useDispatchSpy.mockReturnValue(useDispatchMock);
+    }));
+    (useAppDispatch as jest.Mock).mockImplementation(() => useDispatchMock);
 
     await act(() => renderComponent(clusterTopicNewPath(clusterName)));
-
     await act(() => {
       userEvent.type(screen.getByPlaceholderText('Topic Name'), topicName);
     });
-
     await act(() => {
       userEvent.click(screen.getByText('Create topic'));
     });
-
-    await waitFor(() => expect(mockNavigate).toBeCalledTimes(1));
-    expect(mockNavigate).toHaveBeenLastCalledWith(`../${topicName}`);
-    expect(useDispatchMock).toHaveBeenCalledTimes(1);
+    await waitFor(() => expect(useDispatchMock).toHaveBeenCalledTimes(1));
+    await waitFor(() =>
+      expect(mockNavigate).toHaveBeenLastCalledWith(`../${topicName}`)
+    );
   });
 
   it('does not redirect page when request is not fulfilled', async () => {
-    const useDispatchSpy = jest.spyOn(redux, 'useDispatch');
     const useDispatchMock = jest.fn(() => ({
       meta: { requestStatus: 'pending' },
-    })) as jest.Mock;
-
-    useDispatchSpy.mockReturnValue(useDispatchMock);
+    }));
+    (useAppDispatch as jest.Mock).mockImplementation(() => useDispatchMock);
     await act(() => renderComponent(clusterTopicNewPath(clusterName)));
     await act(() =>
       userEvent.type(screen.getByPlaceholderText('Topic Name'), topicName)
@@ -130,9 +104,8 @@ describe('New', () => {
   });
 
   it('submits valid form that result in an error', async () => {
-    const useDispatchSpy = jest.spyOn(redux, 'useDispatch');
     const useDispatchMock = jest.fn();
-    useDispatchSpy.mockReturnValue(useDispatchMock);
+    (useAppDispatch as jest.Mock).mockImplementation(() => useDispatchMock);
 
     await act(() => renderComponent(clusterTopicNewPath(clusterName)));
     await act(() => {

+ 0 - 36
kafka-ui-react-app/src/components/Topics/New/__test__/fixtures.ts

@@ -1,36 +0,0 @@
-import { CleanUpPolicy, Topic } from 'generated-sources';
-
-export const createTopicPayload: Record<string, unknown> = {
-  name: 'test-topic',
-  partitions: 1,
-  replicationFactor: 1,
-  configs: {
-    'cleanup.policy': 'delete',
-    'retention.ms': '604800000',
-    'retention.bytes': '-1',
-    'max.message.bytes': '1000012',
-    'min.insync.replicas': '1',
-  },
-};
-
-export const createTopicResponsePayload: Topic = {
-  name: 'local',
-  internal: false,
-  partitionCount: 1,
-  replicationFactor: 1,
-  replicas: 1,
-  inSyncReplicas: 1,
-  segmentSize: 0,
-  segmentCount: 0,
-  underReplicatedPartitions: 0,
-  cleanUpPolicy: CleanUpPolicy.DELETE,
-  partitions: [
-    {
-      partition: 0,
-      leader: 1,
-      replicas: [{ broker: 1, leader: false, inSync: true }],
-      offsetMax: 0,
-      offsetMin: 0,
-    },
-  ],
-};

+ 2 - 3
kafka-ui-react-app/src/components/Topics/Topic/Details/Details.tsx

@@ -11,7 +11,6 @@ import {
 } from 'lib/paths';
 import ClusterContext from 'components/contexts/ClusterContext';
 import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal';
-import { useDispatch } from 'react-redux';
 import PageHeading from 'components/common/PageHeading/PageHeading';
 import { Button } from 'components/common/Button/Button';
 import Dropdown from 'components/common/Dropdown/Dropdown';
@@ -20,7 +19,7 @@ import DropdownItem from 'components/common/Dropdown/DropdownItem';
 import styled from 'styled-components';
 import Navbar from 'components/common/Navigation/Navbar.styled';
 import * as S from 'components/Topics/Topic/Details/Details.styled';
-import { useAppSelector } from 'lib/hooks/redux';
+import { useAppDispatch, useAppSelector } from 'lib/hooks/redux';
 import {
   getIsTopicDeletePolicy,
   getIsTopicInternal,
@@ -72,7 +71,7 @@ const Details: React.FC<Props> = ({
   );
 
   const navigate = useNavigate();
-  const dispatch = useDispatch();
+  const dispatch = useAppDispatch();
   const { isReadOnly, isTopicDeletionAllowed } =
     React.useContext(ClusterContext);
   const [isDeleteTopicConfirmationVisible, setDeleteTopicConfirmationVisible] =

+ 3 - 3
kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/MessagesTable.tsx

@@ -3,20 +3,20 @@ import { Table } from 'components/common/table/Table/Table.styled';
 import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
 import { TopicMessage } from 'generated-sources';
 import React, { useContext } from 'react';
-import { useSelector } from 'react-redux';
 import {
   getTopicMessges,
   getIsTopicMessagesFetching,
 } from 'redux/reducers/topicMessages/selectors';
 import TopicMessagesContext from 'components/contexts/TopicMessagesContext';
+import { useAppSelector } from 'lib/hooks/redux';
 
 import Message from './Message';
 
 const MessagesTable: React.FC = () => {
   const { isLive } = useContext(TopicMessagesContext);
 
-  const messages = useSelector(getTopicMessges);
-  const isFetching = useSelector(getIsTopicMessagesFetching);
+  const messages = useAppSelector(getTopicMessges);
+  const isFetching = useAppSelector(getIsTopicMessagesFetching);
 
   return (
     <Table isFullwidth>

+ 1 - 1
kafka-ui-react-app/src/lib/fixtures/kafkaConnect.ts

@@ -104,7 +104,7 @@ export const tasks: Task[] = [
   {
     id: { connector: 'first', task: 4 },
     status: {
-      id: 3,
+      id: 4,
       state: ConnectorTaskStatus.PAUSED,
       workerId: 'kafka-connect0:8083',
     },

+ 0 - 5
kafka-ui-react-app/src/lib/testHelpers.tsx

@@ -13,7 +13,6 @@ import { AnyAction, Store } from 'redux';
 import { RootState } from 'redux/interfaces';
 import { configureStore } from '@reduxjs/toolkit';
 import rootReducer from 'redux/reducers';
-import mockStoreCreator from 'redux/store/configureStore/mockStoreCreator';
 import { QueryClient, QueryClientProvider, UseQueryResult } from 'react-query';
 
 interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
@@ -100,7 +99,3 @@ export class EventSourceMock {
     this.close = jest.fn();
   }
 }
-
-export const getTypeAndPayload = (store: typeof mockStoreCreator) => {
-  return store.getActions().map(({ type, payload }) => ({ type, payload }));
-};

+ 0 - 945
kafka-ui-react-app/src/redux/reducers/topics/__test__/reducer.spec.ts

@@ -1,945 +0,0 @@
-import {
-  MessageSchemaSourceEnum,
-  SortOrder,
-  TopicColumnsToSort,
-  ConfigSource,
-} from 'generated-sources';
-import reducer, {
-  clearTopicsMessages,
-  setTopicsSearch,
-  setTopicsOrderBy,
-  fetchTopicConsumerGroups,
-  fetchTopicMessageSchema,
-  recreateTopic,
-  createTopic,
-  deleteTopic,
-  fetchTopicsList,
-  fetchTopicDetails,
-  fetchTopicConfig,
-  updateTopic,
-  updateTopicPartitionsCount,
-  updateTopicReplicationFactor,
-  deleteTopics,
-} from 'redux/reducers/topics/topicsSlice';
-import {
-  createTopicPayload,
-  createTopicResponsePayload,
-} from 'components/Topics/New/__test__/fixtures';
-import { consumerGroupPayload } from 'redux/reducers/consumerGroups/__test__/fixtures';
-import fetchMock from 'fetch-mock-jest';
-import mockStoreCreator from 'redux/store/configureStore/mockStoreCreator';
-import { getTypeAndPayload } from 'lib/testHelpers';
-import {
-  alertAdded,
-  showSuccessAlert,
-} from 'redux/reducers/alerts/alertsSlice';
-
-const topic = {
-  name: 'topic',
-};
-
-const messageSchema = {
-  key: {
-    name: 'key',
-    source: MessageSchemaSourceEnum.SCHEMA_REGISTRY,
-    schema: `{
-"$schema": "http://json-schema.org/draft-07/schema#",
-"$id": "http://example.com/myURI.schema.json",
-"title": "TestRecord",
-"type": "object",
-"additionalProperties": false,
-"properties": {
-  "f1": {
-    "type": "integer"
-  },
-  "f2": {
-    "type": "string"
-  },
-  "schema": {
-    "type": "string"
-  }
-}
-}
-`,
-  },
-  value: {
-    name: 'value',
-    source: MessageSchemaSourceEnum.SCHEMA_REGISTRY,
-    schema: `{
-"$schema": "http://json-schema.org/draft-07/schema#",
-"$id": "http://example.com/myURI1.schema.json",
-"title": "TestRecord",
-"type": "object",
-"additionalProperties": false,
-"properties": {
-  "f1": {
-    "type": "integer"
-  },
-  "f2": {
-    "type": "string"
-  },
-  "schema": {
-    "type": "string"
-  }
-}
-}
-`,
-  },
-};
-
-const config = [
-  {
-    name: 'compression.type',
-    value: 'producer',
-    defaultValue: 'producer',
-    source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
-    isSensitive: false,
-    isReadOnly: false,
-    synonyms: [
-      {
-        name: 'compression.type',
-        value: 'producer',
-        source: ConfigSource.DYNAMIC_TOPIC_CONFIG,
-      },
-      {
-        name: 'compression.type',
-        value: 'producer',
-        source: ConfigSource.DEFAULT_CONFIG,
-      },
-    ],
-  },
-];
-const details = {
-  name: 'local',
-  internal: false,
-  partitionCount: 1,
-  replicationFactor: 1,
-  replicas: 1,
-  inSyncReplicas: 1,
-  segmentSize: 0,
-  segmentCount: 0,
-  cleanUpPolicy: 'DELETE',
-  partitions: [
-    {
-      partition: 0,
-      leader: 1,
-      replicas: [{ broker: 1, leader: false, inSync: true }],
-      offsetMax: 0,
-      offsetMin: 0,
-    },
-  ],
-  bytesInPerSec: 0.1,
-  bytesOutPerSec: 0.1,
-};
-
-let state = {
-  byName: {
-    [topic.name]: topic,
-  },
-  allNames: [topic.name],
-  messages: [],
-  totalPages: 1,
-  search: '',
-  orderBy: null,
-  sortOrder: SortOrder.ASC,
-  consumerGroups: [],
-};
-const clusterName = 'local';
-
-describe('topics Slice', () => {
-  describe('topics reducer', () => {
-    describe('fetch topic details', () => {
-      it('fetchTopicDetails/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: fetchTopicDetails.fulfilled,
-            payload: {
-              clusterName,
-              topicName: topic.name,
-              topicDetails: details,
-            },
-          })
-        ).toEqual({
-          ...state,
-          byName: {
-            [topic.name]: {
-              ...topic,
-              ...details,
-            },
-          },
-          allNames: [topic.name],
-        });
-      });
-    });
-    describe('fetch topics', () => {
-      it('fetchTopicsList/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: fetchTopicsList.fulfilled,
-            payload: { clusterName, topicName: topic.name },
-          })
-        ).toEqual({
-          ...state,
-          byName: { topic },
-          allNames: [topic.name],
-        });
-      });
-    });
-    describe('fetch topic config', () => {
-      it('fetchTopicConfig/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: fetchTopicConfig.fulfilled,
-            payload: {
-              clusterName,
-              topicName: topic.name,
-              topicConfig: config,
-            },
-          })
-        ).toEqual({
-          ...state,
-          byName: {
-            [topic.name]: {
-              ...topic,
-              config: config.map((conf) => ({ ...conf })),
-            },
-          },
-          allNames: [topic.name],
-        });
-      });
-    });
-    describe('update topic', () => {
-      it('updateTopic/fulfilled', () => {
-        const updatedTopic = {
-          name: 'topic',
-          partitions: 1,
-        };
-        expect(
-          reducer(state, {
-            type: updateTopic.fulfilled,
-            payload: {
-              clusterName,
-              topicName: topic.name,
-              topic: updatedTopic,
-            },
-          })
-        ).toEqual({
-          ...state,
-          byName: {
-            [topic.name]: {
-              ...updatedTopic,
-            },
-          },
-        });
-      });
-    });
-    describe('delete topic', () => {
-      it('deleteTopic/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: deleteTopic.fulfilled,
-            payload: { clusterName, topicName: topic.name },
-          })
-        ).toEqual({
-          ...state,
-          byName: {},
-          allNames: [],
-        });
-      });
-
-      it('clearTopicsMessages/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: clearTopicsMessages.fulfilled,
-            payload: { clusterName, topicName: topic.name },
-          })
-        ).toEqual({
-          ...state,
-          messages: [],
-        });
-      });
-
-      it('recreateTopic/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: recreateTopic.fulfilled,
-            payload: { topic, topicName: topic.name },
-          })
-        ).toEqual({
-          ...state,
-          byName: {
-            [topic.name]: topic,
-          },
-        });
-      });
-    });
-
-    describe('create topics', () => {
-      it('createTopic/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: createTopic.fulfilled,
-            payload: { clusterName, data: createTopicPayload },
-          })
-        ).toEqual({
-          ...state,
-        });
-      });
-    });
-
-    describe('search topics', () => {
-      it('setTopicsSearch', () => {
-        expect(
-          reducer(state, {
-            type: setTopicsSearch,
-            payload: 'test',
-          })
-        ).toEqual({
-          ...state,
-          search: 'test',
-        });
-      });
-    });
-
-    describe('order topics', () => {
-      it('setTopicsOrderBy', () => {
-        expect(
-          reducer(state, {
-            type: setTopicsOrderBy,
-            payload: TopicColumnsToSort.NAME,
-          })
-        ).toEqual({
-          ...state,
-          orderBy: TopicColumnsToSort.NAME,
-        });
-      });
-    });
-
-    describe('topic consumer groups', () => {
-      it('fetchTopicConsumerGroups/fulfilled', () => {
-        expect(
-          reducer(state, {
-            type: fetchTopicConsumerGroups.fulfilled,
-            payload: {
-              clusterName,
-              topicName: topic.name,
-              consumerGroups: consumerGroupPayload,
-            },
-          })
-        ).toEqual({
-          ...state,
-          byName: {
-            [topic.name]: {
-              ...topic,
-              ...consumerGroupPayload,
-            },
-          },
-        });
-      });
-    });
-
-    describe('message sending', () => {
-      it('fetchTopicMessageSchema/fulfilled', () => {
-        state = {
-          byName: {
-            [topic.name]: topic,
-          },
-          allNames: [topic.name],
-          messages: [],
-          totalPages: 1,
-          search: '',
-          orderBy: null,
-          sortOrder: SortOrder.ASC,
-          consumerGroups: [],
-        };
-        expect(
-          reducer(state, {
-            type: fetchTopicMessageSchema.fulfilled,
-            payload: { topicName: topic.name, schema: messageSchema },
-          }).byName
-        ).toEqual({
-          [topic.name]: { ...topic, messageSchema },
-        });
-      });
-    });
-  });
-  describe('Thunks', () => {
-    const store = mockStoreCreator;
-    const topicName = topic.name;
-    const RealDate = Date.now;
-
-    beforeAll(() => {
-      global.Date.now = jest.fn(() =>
-        new Date('2019-04-07T10:20:30Z').getTime()
-      );
-    });
-    afterAll(() => {
-      global.Date.now = RealDate;
-    });
-    afterEach(() => {
-      fetchMock.restore();
-      store.clearActions();
-    });
-    describe('fetchTopicsList', () => {
-      const topicResponse = {
-        pageCount: 1,
-        topics: [createTopicResponsePayload],
-      };
-      it('fetchTopicsList/fulfilled', async () => {
-        fetchMock.getOnce(`/api/clusters/${clusterName}/topics`, topicResponse);
-        await store.dispatch(fetchTopicsList({ clusterName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicsList.pending.type },
-          {
-            type: fetchTopicsList.fulfilled.type,
-            payload: { ...topicResponse },
-          },
-        ]);
-      });
-      it('fetchTopicsList/rejected', async () => {
-        fetchMock.getOnce(`/api/clusters/${clusterName}/topics`, 404);
-        await store.dispatch(fetchTopicsList({ clusterName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicsList.pending.type },
-          {
-            type: fetchTopicsList.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('fetchTopicDetails', () => {
-      it('fetchTopicDetails/fulfilled', async () => {
-        fetchMock.getOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          details
-        );
-        await store.dispatch(fetchTopicDetails({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicDetails.pending.type },
-          {
-            type: fetchTopicDetails.fulfilled.type,
-            payload: { topicDetails: { ...details }, topicName },
-          },
-        ]);
-      });
-      it('fetchTopicDetails/rejected', async () => {
-        fetchMock.getOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          404
-        );
-        await store.dispatch(fetchTopicDetails({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicDetails.pending.type },
-          {
-            type: fetchTopicDetails.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('fetchTopicConfig', () => {
-      it('fetchTopicConfig/fulfilled', async () => {
-        fetchMock.getOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/config`,
-          config
-        );
-        await store.dispatch(fetchTopicConfig({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicConfig.pending.type },
-          {
-            type: fetchTopicConfig.fulfilled.type,
-            payload: {
-              topicConfig: config,
-              topicName,
-            },
-          },
-        ]);
-      });
-      it('fetchTopicConfig/rejected', async () => {
-        fetchMock.getOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/config`,
-          404
-        );
-        await store.dispatch(fetchTopicConfig({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicConfig.pending.type },
-          {
-            type: fetchTopicConfig.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}/config`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('deleteTopic', () => {
-      it('deleteTopic/fulfilled', async () => {
-        fetchMock.deleteOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          topicName
-        );
-        await store.dispatch(deleteTopic({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: deleteTopic.pending.type },
-          { type: showSuccessAlert.pending.type },
-          {
-            type: alertAdded.type,
-            payload: {
-              id: 'message-topic-local',
-              title: '',
-              type: 'success',
-              createdAt: global.Date.now(),
-              message: 'Topic successfully deleted!',
-            },
-          },
-          { type: showSuccessAlert.fulfilled.type },
-          {
-            type: deleteTopic.fulfilled.type,
-            payload: { topicName },
-          },
-        ]);
-      });
-      it('deleteTopic/rejected', async () => {
-        fetchMock.deleteOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          404
-        );
-        await store.dispatch(deleteTopic({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: deleteTopic.pending.type },
-          {
-            type: deleteTopic.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('deleteTopics', () => {
-      it('deleteTopics/fulfilled', async () => {
-        fetchMock.delete(`/api/clusters/${clusterName}/topics/${topicName}`, [
-          topicName,
-          'topic2',
-        ]);
-        await store.dispatch(
-          deleteTopics({ clusterName, topicNames: [topicName, 'topic2'] })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: deleteTopics.pending.type },
-          { type: deleteTopic.pending.type },
-          { type: deleteTopic.pending.type },
-          { type: fetchTopicsList.pending.type },
-          { type: deleteTopics.fulfilled.type },
-        ]);
-      });
-    });
-    describe('recreateTopic', () => {
-      const recreateResponse = {
-        cleanUpPolicy: 'DELETE',
-        inSyncReplicas: 1,
-        internal: false,
-        name: topicName,
-        partitionCount: 1,
-        partitions: undefined,
-        replicas: 1,
-        replicationFactor: 1,
-        segmentCount: 0,
-        segmentSize: 0,
-        underReplicatedPartitions: undefined,
-      };
-      it('recreateTopic/fulfilled', async () => {
-        fetchMock.postOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          recreateResponse
-        );
-        await store.dispatch(recreateTopic({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: recreateTopic.pending.type },
-          { type: showSuccessAlert.pending.type },
-          {
-            type: alertAdded.type,
-            payload: {
-              id: 'message-topic-local',
-              title: '',
-              type: 'success',
-              createdAt: global.Date.now(),
-              message: 'Topic successfully recreated!',
-            },
-          },
-          { type: showSuccessAlert.fulfilled.type },
-          {
-            type: recreateTopic.fulfilled.type,
-            payload: { [topicName]: { ...recreateResponse } },
-          },
-        ]);
-      });
-      it('recreateTopic/rejected', async () => {
-        fetchMock.postOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          404
-        );
-        await store.dispatch(recreateTopic({ clusterName, topicName }));
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: recreateTopic.pending.type },
-          {
-            type: recreateTopic.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('fetchTopicConsumerGroups', () => {
-      const consumerGroups = [
-        {
-          groupId: 'groupId1',
-          members: 0,
-          topics: 1,
-          simple: false,
-          partitionAssignor: '',
-          coordinator: {
-            id: 1,
-            port: undefined,
-            host: 'host',
-          },
-          messagesBehind: undefined,
-          state: undefined,
-        },
-        {
-          groupId: 'groupId2',
-          members: 0,
-          topics: 1,
-          simple: false,
-          partitionAssignor: '',
-          coordinator: {
-            id: 1,
-            port: undefined,
-            host: 'host',
-          },
-          messagesBehind: undefined,
-          state: undefined,
-        },
-      ];
-      it('fetchTopicConsumerGroups/fulfilled', async () => {
-        fetchMock.getOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/consumer-groups`,
-          consumerGroups
-        );
-        await store.dispatch(
-          fetchTopicConsumerGroups({ clusterName, topicName })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicConsumerGroups.pending.type },
-          {
-            type: fetchTopicConsumerGroups.fulfilled.type,
-            payload: { consumerGroups, topicName },
-          },
-        ]);
-      });
-      it('fetchTopicConsumerGroups/rejected', async () => {
-        fetchMock.getOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/consumer-groups`,
-          404
-        );
-        await store.dispatch(
-          fetchTopicConsumerGroups({ clusterName, topicName })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: fetchTopicConsumerGroups.pending.type },
-          {
-            type: fetchTopicConsumerGroups.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}/consumer-groups`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('updateTopicPartitionsCount', () => {
-      it('updateTopicPartitionsCount/fulfilled', async () => {
-        fetchMock.patchOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/partitions`,
-          { message: 'success' }
-        );
-        await store.dispatch(
-          updateTopicPartitionsCount({
-            clusterName,
-            topicName,
-            partitions: 1,
-          })
-        );
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: updateTopicPartitionsCount.pending.type },
-          { type: showSuccessAlert.pending.type },
-          {
-            type: alertAdded.type,
-            payload: {
-              id: 'message-topic-local-1',
-              title: '',
-              type: 'success',
-              createdAt: global.Date.now(),
-              message: 'Number of partitions successfully increased!',
-            },
-          },
-          { type: fetchTopicDetails.pending.type },
-          { type: showSuccessAlert.fulfilled.type },
-          {
-            type: updateTopicPartitionsCount.fulfilled.type,
-          },
-        ]);
-      });
-      it('updateTopicPartitionsCount/rejected', async () => {
-        fetchMock.patchOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/partitions`,
-          404
-        );
-        await store.dispatch(
-          updateTopicPartitionsCount({
-            clusterName,
-            topicName,
-            partitions: 1,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: updateTopicPartitionsCount.pending.type },
-          {
-            type: updateTopicPartitionsCount.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}/partitions`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('updateTopicReplicationFactor', () => {
-      it('updateTopicReplicationFactor/fulfilled', async () => {
-        fetchMock.patchOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/replications`,
-          { message: 'success' }
-        );
-        await store.dispatch(
-          updateTopicReplicationFactor({
-            clusterName,
-            topicName,
-            replicationFactor: 1,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: updateTopicReplicationFactor.pending.type },
-          {
-            type: updateTopicReplicationFactor.fulfilled.type,
-          },
-        ]);
-      });
-      it('updateTopicReplicationFactor/rejected', async () => {
-        fetchMock.patchOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/replications`,
-          404
-        );
-        await store.dispatch(
-          updateTopicReplicationFactor({
-            clusterName,
-            topicName,
-            replicationFactor: 1,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: updateTopicReplicationFactor.pending.type },
-          {
-            type: updateTopicReplicationFactor.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}/replications`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('createTopic', () => {
-      const newTopic = {
-        name: 'newTopic',
-        partitions: 0,
-        replicationFactor: 0,
-        minInSyncReplicas: 0,
-        cleanupPolicy: 'DELETE',
-        retentionMs: 1,
-        retentionBytes: 1,
-        maxMessageBytes: 1,
-        customParams: [
-          {
-            name: '',
-            value: '',
-          },
-        ],
-      };
-      it('createTopic/fulfilled', async () => {
-        fetchMock.postOnce(`/api/clusters/${clusterName}/topics`, {
-          message: 'success',
-        });
-        await store.dispatch(
-          createTopic({
-            clusterName,
-            data: newTopic,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: createTopic.pending.type },
-          {
-            type: createTopic.fulfilled.type,
-          },
-        ]);
-      });
-      it('createTopic/rejected', async () => {
-        fetchMock.postOnce(`/api/clusters/${clusterName}/topics`, 404);
-        await store.dispatch(
-          createTopic({
-            clusterName,
-            data: newTopic,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: createTopic.pending.type },
-          {
-            type: createTopic.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('updateTopic', () => {
-      const updateTopicResponse = {
-        name: topicName,
-        partitions: 0,
-        replicationFactor: 0,
-        minInSyncReplicas: 0,
-        cleanupPolicy: 'DELETE',
-        retentionMs: 0,
-        retentionBytes: 0,
-        maxMessageBytes: 0,
-        customParams: {
-          byIndex: {},
-          allIndexes: [],
-        },
-      };
-      it('updateTopic/fulfilled', async () => {
-        fetchMock.patchOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          createTopicResponsePayload
-        );
-        await store.dispatch(
-          updateTopic({
-            clusterName,
-            topicName,
-            form: updateTopicResponse,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: updateTopic.pending.type },
-          {
-            type: updateTopic.fulfilled.type,
-            payload: { [topicName]: { ...createTopicResponsePayload } },
-          },
-        ]);
-      });
-      it('updateTopic/rejected', async () => {
-        fetchMock.patchOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}`,
-          404
-        );
-        await store.dispatch(
-          updateTopic({
-            clusterName,
-            topicName,
-            form: updateTopicResponse,
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: updateTopic.pending.type },
-          {
-            type: updateTopic.rejected.type,
-            payload: {
-              status: 404,
-              statusText: 'Not Found',
-              url: `/api/clusters/${clusterName}/topics/${topicName}`,
-              message: undefined,
-            },
-          },
-        ]);
-      });
-    });
-    describe('clearTopicsMessages', () => {
-      it('clearTopicsMessages/fulfilled', async () => {
-        fetchMock.deleteOnce(
-          `/api/clusters/${clusterName}/topics/${topicName}/messages`,
-          [topicName, 'topic2']
-        );
-        await store.dispatch(
-          clearTopicsMessages({
-            clusterName,
-            topicNames: [topicName, 'topic2'],
-          })
-        );
-
-        expect(getTypeAndPayload(store)).toEqual([
-          { type: clearTopicsMessages.pending.type },
-          { type: clearTopicsMessages.fulfilled.type },
-        ]);
-      });
-    });
-  });
-});

+ 0 - 12
kafka-ui-react-app/src/redux/store/configureStore/mockStoreCreator.ts

@@ -1,12 +0,0 @@
-import configureMockStore, { MockStoreCreator } from 'redux-mock-store';
-import thunk, { ThunkDispatch } from 'redux-thunk';
-import { AnyAction, Middleware } from 'redux';
-import { RootState } from 'redux/interfaces';
-
-const middlewares: Array<Middleware> = [thunk];
-type DispatchExts = ThunkDispatch<RootState, undefined, AnyAction>;
-
-const mockStoreCreator: MockStoreCreator<RootState, DispatchExts> =
-  configureMockStore<RootState, DispatchExts>(middlewares);
-
-export default mockStoreCreator();

+ 2 - 3
kafka-ui-react-app/vite.config.ts

@@ -15,12 +15,11 @@ export default defineConfig(({ mode }) => {
       rollupOptions: {
         output: {
           manualChunks: {
-            venod: [
+            vendor: [
               'react',
               'react-router-dom',
               'react-dom',
               'redux',
-              'redux-thunk',
               'react-redux',
               'styled-components',
               'react-ace',
@@ -32,7 +31,7 @@ export default defineConfig(({ mode }) => {
     define: {
       'process.env.NODE_ENV': `"${mode}"`,
       'process.env.VITE_TAG': `"${process.env.VITE_TAG}"`,
-      'process.env.GIT_COMMIT': `"${process.env.VITE_COMMIT}"`,
+      'process.env.VITE_COMMIT': `"${process.env.VITE_COMMIT}"`,
     },
   };
   const proxy = process.env.VITE_DEV_PROXY;