Upgrade redux (#2299)

* got rid of redux-thunk

* Bump redux

* Bump ace. Got rid of node-fetch

* Fix vite config
This commit is contained in:
Oleg Shur 2022-07-19 16:18:28 +03:00 committed by GitHub
parent dfe12807e2
commit 96b00785b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 97 additions and 1139 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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