From 4f3400e5945345589ffdc850bc0dcf50a5c1ec86 Mon Sep 17 00:00:00 2001 From: Vyrtsev Mikhail Date: Sun, 29 Sep 2019 23:40:05 +0300 Subject: [PATCH 1/4] update Comment type --- frontend/app/common/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/app/common/types.ts b/frontend/app/common/types.ts index 66f181e6..e55684a7 100644 --- a/frontend/app/common/types.ts +++ b/frontend/app/common/types.ts @@ -44,6 +44,7 @@ export interface Comment { locator: Locator; /** comment score, read only */ score: number; + voted_ips: { Timestamp: string; Value: boolean }[]; /** * vote delta, * if user hasn't voted delta will be 0, From 4240a4d6ee99af642db3ae508b3824fe6d164072 Mon Sep 17 00:00:00 2001 From: Vyrtsev Mikhail Date: Sun, 6 Oct 2019 18:36:36 +0300 Subject: [PATCH 2/4] update minor deps --- frontend/package-lock.json | 333 +++++++++++++++++++++++-------------- frontend/package.json | 26 +-- 2 files changed, 224 insertions(+), 135 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 56fc5d8f..d33a64f8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1668,28 +1668,28 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.2.tgz", - "integrity": "sha512-wrIBsjA5pl13f0RN4Zx4FNWmU71lv03meGKnqRUoCyan17s4V3WL92f3w3AIuWbNnpcrQyFBU5qMavJoB8d27w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.2", + "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.2.tgz", - "integrity": "sha512-z8+wGWV2dgUhLqrtRYa03yDx4HWMvXKi1z8g3m2JyxAx8F7xk74asqPk5LAETjqDSGLFML/6CDl0+yFunSYicw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.3.tgz", - "integrity": "sha512-l6t8xEhfK9Sa4YO5mIRdau7XSOADfmh3jCr0evNHdY+HNkW6xuQhgMH7D73VV6WpZOagrW0UludvMTiifiwTfA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.2", + "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" } }, @@ -1852,9 +1852,9 @@ "dev": true }, "@types/node": { - "version": "12.7.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz", - "integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==", + "version": "12.7.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.11.tgz", + "integrity": "sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==", "dev": true }, "@types/normalize-package-data": { @@ -1935,12 +1935,12 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.3.1.tgz", - "integrity": "sha512-VqVNEsvemviajlaWm03kVMabc6S3xCHGYuY0fReTrIIOZg+3WzB+wfw6fD3KYKerw5lYxmzogmHOZ0i7YKnuwA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.3.2.tgz", + "integrity": "sha512-tcnpksq1bXzcIRbYLeXkgp6l+ggEMXXUcl1wsSvL807fRtmvVQKygElwEUf4hBA76dNag3VAK1q2m3vd7qJaZA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.3.1", + "@typescript-eslint/experimental-utils": "2.3.2", "eslint-utils": "^1.4.2", "functional-red-black-tree": "^1.0.1", "regexpp": "^2.0.1", @@ -1948,13 +1948,13 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.1.tgz", - "integrity": "sha512-FaZEj73o4h6Wd0Lg+R4pZiJGdR0ZYbJr+O2+RbQ1aZjX8bZcfkVDtD+qm74Dv77rfSKkDKE64UTziLBo9UYHQA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.3.2.tgz", + "integrity": "sha512-t+JGdTT6dRbmvKDlhlVkEueoZa0fhJNfG6z2cpnRPLwm3VwYr2BjR//acJGC1Yza0I9ZNcDfRY7ubQEvvfG6Jg==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.3.1", + "@typescript-eslint/typescript-estree": "2.3.2", "eslint-scope": "^5.0.0" }, "dependencies": { @@ -1971,14 +1971,14 @@ } }, "@typescript-eslint/parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.3.1.tgz", - "integrity": "sha512-ZlWdzhCJ2iZnSp/VBAJ/sowFbyHycIux8t0UEH0JsKgQvfSf7949hLYFMwTXdCMeEnpP1zRTHimrR+YHzs8LIw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.3.2.tgz", + "integrity": "sha512-nq1UQeNGdKdqdgF6Ww+Ov2OidWgiL96+JYdXXZ2rkP/OWyc6KMNSbs6MpRCpI8q+PmDa7hBnHNQIo7w/drYccA==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.3.1", - "@typescript-eslint/typescript-estree": "2.3.1", + "@typescript-eslint/experimental-utils": "2.3.2", + "@typescript-eslint/typescript-estree": "2.3.2", "eslint-visitor-keys": "^1.1.0" }, "dependencies": { @@ -1991,9 +1991,9 @@ } }, "@typescript-eslint/typescript-estree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.1.tgz", - "integrity": "sha512-9SFhUgFuePJBB6jlLkOPPhMkZNiDCr+S8Ft7yAkkP2c5x5bxPhG3pe/exMiQaF8IGyVMDW6Ul0q4/cZ+uF3uog==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.3.2.tgz", + "integrity": "sha512-eZNEAai16nwyhIVIEaWQlaUgAU3S9CkQ58qvK0+3IuSdLJD3W1PNuehQFMIhW/mTP1oFR9GNoTcLg7gtXz6lzA==", "dev": true, "requires": { "glob": "^7.1.4", @@ -2262,13 +2262,13 @@ "dev": true }, "aggregate-error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.0.tgz", - "integrity": "sha512-yKD9kEoJIR+2IFqhMwayIBgheLYbB3PS2OBhWae1L/ODTd/JF/30cW0bc9TqzRL3k4U41Dieu3BF4I29p8xesA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", "dev": true, "requires": { "clean-stack": "^2.0.0", - "indent-string": "^3.2.0" + "indent-string": "^4.0.0" } }, "ajv": { @@ -2588,24 +2588,56 @@ "dev": true }, "autoprefixer": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", - "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.4.tgz", + "integrity": "sha512-Koz2cJU9dKOxG8P1f8uVaBntOv9lP4yz9ffWvWaicv9gHBPhpQB22nGijwd8gqW9CNT+UdkbQOQNLVI8jN1ZfQ==", "dev": true, "requires": { - "browserslist": "^4.6.3", - "caniuse-lite": "^1.0.30000980", + "browserslist": "^4.7.0", + "caniuse-lite": "^1.0.30000998", "chalk": "^2.4.2", "normalize-range": "^0.1.2", "num2fraction": "^1.2.2", - "postcss": "^7.0.17", - "postcss-value-parser": "^4.0.0" + "postcss": "^7.0.18", + "postcss-value-parser": "^4.0.2" }, "dependencies": { + "browserslist": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz", + "integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000989", + "electron-to-chromium": "^1.3.247", + "node-releases": "^1.1.29" + } + }, + "caniuse-lite": { + "version": "1.0.30000999", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000999.tgz", + "integrity": "sha512-1CUyKyecPeksKwXZvYw0tEoaMCo/RwBlXmEtN5vVnabvO0KPd9RQLcaAuR9/1F+KDMv6esmOFWlsXuzDk+8rxg==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.275", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.275.tgz", + "integrity": "sha512-/YWtW/VapMnuYA1lNOaa1F4GhR1LBf+CUTp60lzDPEEh0XOzyOAyULyYZVF9vziZ3qSbTqCwmKwsyRXp66STbw==", + "dev": true + }, + "node-releases": { + "version": "1.1.34", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.34.tgz", + "integrity": "sha512-fNn12JTEfniTuCqo0r9jXgl44+KxRH/huV7zM/KAGOKxDKrHr6EbT7SSs4B+DNxyBE2mks28AD+Jw6PkfY5uwA==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, "postcss": { - "version": "7.0.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", - "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", + "version": "7.0.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.18.tgz", + "integrity": "sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -2614,9 +2646,15 @@ } }, "postcss-value-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz", - "integrity": "sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "source-map": { @@ -4789,9 +4827,9 @@ } }, "enzyme-adapter-preact-pure": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/enzyme-adapter-preact-pure/-/enzyme-adapter-preact-pure-2.0.2.tgz", - "integrity": "sha512-BVfceFghPaYae/Sm2lT7AASLVc5r5aU8II0AyvmhWFR0AY5QERmOnO0BW3PTWVEagreEaZUWnLY6yO408u0WMA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-preact-pure/-/enzyme-adapter-preact-pure-2.1.0.tgz", + "integrity": "sha512-C1kcVqqA9GuSIFTUdX3aXjLoTrr0Z6aUn6DZqFOBhjGtHXOXrCycwsdPaF0x+/y1286/LaZxQvi8iBaMay4/Ew==", "dev": true, "requires": { "array.prototype.flatmap": "^1.2.1", @@ -4920,9 +4958,9 @@ } }, "eslint": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.0.tgz", - "integrity": "sha512-IIbSW+vKOqMatPmS9ayyku4tvWxHY2iricSRtOz6+ZA5IPRlgXzEL0u/j6dr4eha0ugmhMwDTqxtmNu3kj9O4w==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz", + "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -5031,9 +5069,9 @@ } }, "eslint-config-prettier": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.3.0.tgz", - "integrity": "sha512-EWaGjlDAZRzVFveh2Jsglcere2KK5CJBhkNSa1xs3KfMUGdRiT7lG089eqPdvlzWHpAqaekubOsOMu8W8Yk71A==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.4.0.tgz", + "integrity": "sha512-YrKucoFdc7SEko5Sxe4r6ixqXPDP1tunGw91POeZTTRKItf/AMFYt/YLEQtZMkR2LVpAVhcAcZgcWpm1oGPW7w==", "dev": true, "requires": { "get-stdin": "^6.0.0" @@ -5066,20 +5104,20 @@ } }, "eslint-plugin-react": { - "version": "7.14.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz", - "integrity": "sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.16.0.tgz", + "integrity": "sha512-GacBAATewhhptbK3/vTP09CbFrgUJmBSaaRcWdbQLFvUZy9yVcQxigBNHGPU/KE2AyHpzj3AWXpxoMTsIDiHug==", "dev": true, "requires": { "array-includes": "^3.0.3", "doctrine": "^2.1.0", "has": "^1.0.3", - "jsx-ast-utils": "^2.1.0", + "jsx-ast-utils": "^2.2.1", "object.entries": "^1.1.0", "object.fromentries": "^2.0.0", "object.values": "^1.1.0", "prop-types": "^15.7.2", - "resolve": "^1.10.1" + "resolve": "^1.12.0" }, "dependencies": { "doctrine": { @@ -5514,16 +5552,15 @@ "dev": true }, "fast-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz", - "integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.0.tgz", + "integrity": "sha512-TrUz3THiq2Vy3bjfQUB2wNyPdGBeGmdjbzzBLhfHN4YFurYptCKwGq/TfiRavbGywFRzY6U2CdmQ1zmsY5yYaw==", "dev": true, "requires": { - "@nodelib/fs.stat": "^2.0.1", - "@nodelib/fs.walk": "^1.2.1", - "glob-parent": "^5.0.0", - "is-glob": "^4.0.1", - "merge2": "^1.2.3", + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", "micromatch": "^4.0.2" }, "dependencies": { @@ -5621,9 +5658,9 @@ } }, "fetch-mock": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-7.4.0.tgz", - "integrity": "sha512-q2zrAJh2CcPf6yrDIRxAo18vs1yohETzTNVvtJsqznAAWS4XuJ5M8uaIfrw8odHm7wZJIfMdA6P3RObMNYSWXQ==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-7.5.1.tgz", + "integrity": "sha512-yTb46p7y14bfyWCox50lYqs6NRSo7XPOKzsnLzrSOqRWAGLsvF+aAv0dPkTLeKaBeH3aVSVwWeXzMrctXEZVag==", "dev": true, "requires": { "babel-polyfill": "^6.26.0", @@ -6514,9 +6551,9 @@ "dev": true }, "get-own-enumerable-property-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", - "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", + "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", "dev": true }, "get-stdin": { @@ -7071,9 +7108,9 @@ "dev": true }, "husky": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.7.tgz", - "integrity": "sha512-fIrkaREoQk6DO8KnSX16Aq7Kg9SxqYYQZH/9b+4AxXyXNNgpJLsc8lWlQCShLus1nbujIyZ/WQZBHGwClohK/w==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.8.tgz", + "integrity": "sha512-HFOsgcyrX3qe/rBuqyTt+P4Gxn5P0seJmr215LAZ/vnwK3jWB3r0ck7swbzGRUbufCf9w/lgHPVbF/YXQALgfQ==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -7259,9 +7296,9 @@ "dev": true }, "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, "indexes-of": { @@ -7391,9 +7428,9 @@ "dev": true }, "is-absolute-url": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.2.tgz", - "integrity": "sha512-+5g/wLlcm1AcxSP7014m6GvbPHswDx980vD/3bZaap8aGV9Yfs7Q6y6tfaupgZ5O74Byzc8dGrSCJ+bFXx0KdA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", "dev": true }, "is-accessor-descriptor": { @@ -9501,9 +9538,9 @@ "dev": true }, "lint-staged": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.0.tgz", - "integrity": "sha512-jTu1KoGiGTSffM539wK+3igVqDGVsby3KwDBaXL471YndahkjnavLX+R5Nsk49JwklyMo0ZAXay1BaoyA6d2Jw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-9.4.1.tgz", + "integrity": "sha512-zFRbo1bAJEVf1m33paTTjDVfy2v3lICCqHfmQSgNoI+lWpi7HPG5y/R2Y7Whdce+FKxlZYs/U1sDSx8+nmQdDA==", "dev": true, "requires": { "chalk": "^2.4.2", @@ -9569,9 +9606,9 @@ } }, "execa": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.0.4.tgz", - "integrity": "sha512-VcQfhuGD51vQUQtKIq2fjGDLDbL6N1DTQVpYzxZ7LPIXw3HqTuIz6uxRmpV1qf8i31LHf2kjiaGI+GdHwRgbnQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.0.5.tgz", + "integrity": "sha512-SwmwZZyJjflcqLSgllk4EQlMLst2p9muyzwNugKGFlpAz6rZ7M+s2nBR97GAq4Vzjwx2y9rcMcmqzojwN+xwNA==", "dev": true, "requires": { "cross-spawn": "^6.0.5", @@ -9644,9 +9681,9 @@ "dev": true }, "is-path-inside": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.1.tgz", - "integrity": "sha512-CKstxrctq1kUesU6WhtZDbYKzzYBuRH0UYInAVrkc/EYdB9ltbfE0gOoayG9nhohG6447sOOVGhHqsdmBvkbNg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", "dev": true }, "is-stream": { @@ -9816,6 +9853,12 @@ "object-assign": "^4.1.0" } }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "log-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", @@ -10553,9 +10596,9 @@ "dev": true }, "node-forge": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.2.tgz", - "integrity": "sha512-mXQ9GBq1N3uDCyV1pdSzgIguwgtVpM7f5/5J4ipz12PKWElmPpVWLDuWl8iXmhysr21+WmX/OJ5UKx82wjomgg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", "dev": true }, "node-int64": { @@ -10842,15 +10885,41 @@ } }, "object.fromentries": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", - "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.1.tgz", + "integrity": "sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.11.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.15.0", "function-bind": "^1.1.1", - "has": "^1.0.1" + "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.15.0.tgz", + "integrity": "sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } } }, "object.getownpropertydescriptors": { @@ -11765,9 +11834,9 @@ "integrity": "sha512-37tlDJGq5IQKqGUbqPZ7qPtsTOWFyxe+ojAOFfzKo0dEPreenqrqgJuS83zGpeGAqD9h9L9Yr7QuxH2W4ZrKxg==" }, "preact-context": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/preact-context/-/preact-context-1.1.3.tgz", - "integrity": "sha512-2LcpjZG6JUhBgqziVH+nJtmu9PS5KzWoFx6wX2svXw0oBHhU6e8tQZhEkKLMOAxdmj7gVzApfS/B6V+fjJ/llA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/preact-context/-/preact-context-1.1.4.tgz", + "integrity": "sha512-gcCjPJ65R0MiW9hDu8W/3WAmyTElIvwLyEO6oLQiM6/TbLKLxCpBCWV8GJjx52TTEyUr60HLDcmoCXZlslelzQ==", "dev": true }, "preact-redux": { @@ -12546,9 +12615,9 @@ "dev": true }, "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -12616,12 +12685,12 @@ "dev": true }, "selfsigned": { - "version": "1.10.6", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.6.tgz", - "integrity": "sha512-i3+CeqxL7DpAazgVpAGdKMwHuL63B5nhJMh9NQ7xmChGkA3jNFflq6Jyo1LLJYcr3idWiNOPWHCrm4zMayLG4w==", + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", "dev": true, "requires": { - "node-forge": "0.8.2" + "node-forge": "0.9.0" } }, "semver": { @@ -13382,6 +13451,26 @@ "function-bind": "^1.0.2" } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -14664,9 +14753,9 @@ } }, "webpack-dev-middleware": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.1.tgz", - "integrity": "sha512-5MWu9SH1z3hY7oHOV6Kbkz5x7hXbxK56mGHNqHTe6d+ewxOwKUxoUJBs7QIaJb33lPjl9bJZ3X0vCoooUzC36A==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", "dev": true, "requires": { "memory-fs": "^0.4.1", @@ -14685,9 +14774,9 @@ } }, "webpack-dev-server": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.1.tgz", - "integrity": "sha512-9F5DnfFA9bsrhpUCAfQic/AXBVHvq+3gQS+x6Zj0yc1fVVE0erKh2MV4IV12TBewuTrYeeTIRwCH9qLMvdNvTw==", + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.2.tgz", + "integrity": "sha512-0xxogS7n5jHDQWy0WST0q6Ykp7UGj4YvWh+HVN71JoE7BwPxMZrwgraBvmdEMbDVMBzF0u+mEzn8TQzBm5NYJQ==", "dev": true, "requires": { "ansi-html": "0.0.7", @@ -14699,18 +14788,18 @@ "del": "^4.1.1", "express": "^4.17.1", "html-entities": "^1.2.1", - "http-proxy-middleware": "^0.19.1", + "http-proxy-middleware": "0.19.1", "import-local": "^2.0.0", "internal-ip": "^4.3.0", "ip": "^1.1.5", - "is-absolute-url": "^3.0.2", + "is-absolute-url": "^3.0.3", "killable": "^1.0.1", "loglevel": "^1.6.4", "opn": "^5.5.0", "p-retry": "^3.0.1", "portfinder": "^1.0.24", "schema-utils": "^1.0.0", - "selfsigned": "^1.10.6", + "selfsigned": "^1.10.7", "semver": "^6.3.0", "serve-index": "^1.9.1", "sockjs": "0.3.19", @@ -14719,7 +14808,7 @@ "strip-ansi": "^3.0.1", "supports-color": "^6.1.0", "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.1", + "webpack-dev-middleware": "^3.7.2", "webpack-log": "^2.0.0", "ws": "^6.2.1", "yargs": "12.0.5" diff --git a/frontend/package.json b/frontend/package.json index 965ed4a8..dd1ff23b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -38,11 +38,11 @@ "@types/fetch-mock": "^7.3.1", "@types/jest": "^24.0.18", "@types/lodash": "^4.14.141", - "@types/node": "^12.7.8", + "@types/node": "^12.7.11", "@types/redux-mock-store": "^1.0.1", - "@typescript-eslint/eslint-plugin": "^2.3.1", - "@typescript-eslint/parser": "^2.3.1", - "autoprefixer": "^9.6.1", + "@typescript-eslint/eslint-plugin": "^2.3.2", + "@typescript-eslint/parser": "^2.3.2", + "autoprefixer": "^9.6.4", "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", "babel-loader": "^8.0.6", @@ -51,22 +51,22 @@ "css-loader": "^3.2.0", "document-register-element": "^1.14.3", "enzyme": "^3.10.0", - "enzyme-adapter-preact-pure": "^2.0.2", + "enzyme-adapter-preact-pure": "^2.1.0", "es-check": "^5.0.0", - "eslint": "^6.5.0", - "eslint-config-prettier": "^6.3.0", + "eslint": "^6.5.1", + "eslint-config-prettier": "^6.4.0", "eslint-plugin-jsx-a11y": "^6.2.3", "eslint-plugin-prettier": "^3.1.1", - "eslint-plugin-react": "^7.14.3", - "fetch-mock": "^7.4.0", + "eslint-plugin-react": "^7.16.0", + "fetch-mock": "^7.5.1", "file-loader": "^4.2.0", "html-webpack-plugin": "^3.2.0", - "husky": "^3.0.7", + "husky": "^3.0.8", "jest": "^24.9.0", "jest-enzyme": "^7.1.1", "jest-extended": "^0.11.2", "jest-localstorage-mock": "^2.4.0", - "lint-staged": "^9.4.0", + "lint-staged": "^9.4.1", "lodash": "^4.17.15", "mini-css-extract-plugin": "^0.8.0", "node-fetch": "^2.6.0", @@ -79,7 +79,7 @@ "postcss-simple-vars": "^5.0.2", "postcss-url": "^8.0.0", "postcss-wrap": "0.0.4", - "preact-context": "^1.1.3", + "preact-context": "^1.1.4", "prettier": "^1.18.2", "redux-mock-store": "^1.5.3", "style-loader": "^1.0.0", @@ -89,7 +89,7 @@ "webpack": "^4.41.0", "webpack-bundle-analyzer": "^3.5.2", "webpack-cli": "^3.3.9", - "webpack-dev-server": "^3.8.1", + "webpack-dev-server": "^3.8.2", "whatwg-fetch": "^3.0.0" }, "dependencies": { From 02b2895cacd7681899d1e750f0fcef91fe784ed8 Mon Sep 17 00:00:00 2001 From: Vyrtsev Mikhail Date: Sun, 6 Oct 2019 20:44:25 +0300 Subject: [PATCH 3/4] update Preact to Preact X --- .../markdown-toolbar-element/index.d.ts | 18 ---- frontend/app/@types/preact/index.d.ts | 24 +++++ .../auth-panel__anonymous-login-form.tsx | 13 +-- .../auth-panel__email-login-form.test.tsx | 4 +- .../auth-panel__email-login-form.tsx | 51 +++++----- .../__user-id/auth-panel__user-id.tsx | 19 ++-- .../components/auth-panel/auth-panel.test.tsx | 4 +- .../app/components/auth-panel/auth-panel.tsx | 17 ++-- .../components/avatar-icon/avatar-icon.tsx | 4 +- frontend/app/components/button/button.tsx | 12 +-- .../app/components/comment/comment.test.tsx | 4 +- frontend/app/components/comment/comment.tsx | 16 +-- ...ected-comment.ts => connected-comment.tsx} | 47 +++++---- frontend/app/components/countdown/index.tsx | 12 +-- .../dropdown/__item/dropdown__item.tsx | 4 +- frontend/app/components/dropdown/dropdown.tsx | 35 +++---- frontend/app/components/input/input.tsx | 28 +++--- .../markdown-toolbar-icons/bold-icon.tsx | 4 +- .../markdown-toolbar-icons/code-icon.tsx | 4 +- .../markdown-toolbar-icons/header-icon.tsx | 4 +- .../markdown-toolbar-icons/image-icon.tsx | 4 +- .../markdown-toolbar-icons/italic-icon.tsx | 4 +- .../markdown-toolbar-icons/link-icon.tsx | 4 +- .../ordered-list-icon.tsx | 4 +- .../markdown-toolbar-icons/quote-icon.tsx | 4 +- .../unordered-list-icon.tsx | 4 +- .../app/components/input/markdown-toolbar.tsx | 8 +- .../components/input/textarea-autosize.tsx | 6 +- .../list-comments/list-comments.tsx | 4 +- .../components/preloader/preloader.test.tsx | 4 +- .../app/components/preloader/preloader.tsx | 4 +- .../app/components/root/in-view/in-view.tsx | 9 +- frontend/app/components/root/root.tsx | 18 ++-- frontend/app/components/settings/settings.tsx | 8 +- frontend/app/components/thread/thread.tsx | 19 ++-- .../user-info/last-comments-list.tsx | 4 +- .../app/components/user-info/user-info.tsx | 43 ++++---- frontend/app/components/with-theme/index.ts | 15 --- frontend/app/components/with-theme/index.tsx | 23 +++++ frontend/app/hooks/useAction.ts | 32 ++++++ frontend/app/last-comments.tsx | 5 +- frontend/app/remark.tsx | 9 +- frontend/app/store/comments/getters.ts | 2 +- frontend/app/store/thread/getters.ts | 2 +- frontend/app/utils/patchPreactContext.js | 7 -- frontend/jest.config.js | 2 + frontend/package-lock.json | 98 ++++++++++++++++--- frontend/package.json | 6 +- frontend/tsconfig.json | 2 +- frontend/webpack.config.js | 6 +- 50 files changed, 404 insertions(+), 280 deletions(-) delete mode 100644 frontend/app/@types/markdown-toolbar-element/index.d.ts create mode 100644 frontend/app/@types/preact/index.d.ts rename frontend/app/components/comment/{connected-comment.ts => connected-comment.tsx} (64%) delete mode 100644 frontend/app/components/with-theme/index.ts create mode 100644 frontend/app/components/with-theme/index.tsx create mode 100644 frontend/app/hooks/useAction.ts delete mode 100644 frontend/app/utils/patchPreactContext.js diff --git a/frontend/app/@types/markdown-toolbar-element/index.d.ts b/frontend/app/@types/markdown-toolbar-element/index.d.ts deleted file mode 100644 index f4ed19d2..00000000 --- a/frontend/app/@types/markdown-toolbar-element/index.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -declare namespace JSX { - interface IntrinsicElements { - 'markdown-toolbar': { - for: string; - children?: any; - className: string; - }; - 'md-bold': any; - 'md-header': any; - 'md-italic': any; - 'md-quote': any; - 'md-code': any; - 'md-link': any; - 'md-unordered-list': any; - 'md-ordered-list': any; - } -} diff --git a/frontend/app/@types/preact/index.d.ts b/frontend/app/@types/preact/index.d.ts new file mode 100644 index 00000000..442ccaa8 --- /dev/null +++ b/frontend/app/@types/preact/index.d.ts @@ -0,0 +1,24 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unused-vars */ + +import * as preact from 'preact/src/jsx'; + +declare module 'preact/src/jsx' { + namespace JSXInternal { + interface IntrinsicElements { + 'markdown-toolbar': { + for: string; + children?: any; + className: string; + }; + 'md-bold': any; + 'md-header': any; + 'md-italic': any; + 'md-quote': any; + 'md-code': any; + 'md-link': any; + 'md-unordered-list': any; + 'md-ordered-list': any; + } + } +} diff --git a/frontend/app/components/auth-panel/__anonymous-login-form/auth-panel__anonymous-login-form.tsx b/frontend/app/components/auth-panel/__anonymous-login-form/auth-panel__anonymous-login-form.tsx index a3ad4783..856ae95d 100644 --- a/frontend/app/components/auth-panel/__anonymous-login-form/auth-panel__anonymous-login-form.tsx +++ b/frontend/app/components/auth-panel/__anonymous-login-form/auth-panel__anonymous-login-form.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h, Component, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, Component, createRef } from 'preact'; import b from 'bem-react-helper'; import { Theme } from '@app/common/types'; @@ -17,7 +17,7 @@ interface State { export class AnonymousLoginForm extends Component { static usernameRegex = /^[a-zA-Z][\w ]+$/; - inputRef?: HTMLInputElement; + inputRef = createRef(); constructor(props: Props) { super(props); @@ -60,11 +60,12 @@ export class AnonymousLoginForm extends Component { componentDidUpdate() { setTimeout(() => { - this.inputRef && this.inputRef.focus(); + this.inputRef.current && this.inputRef.current.focus(); }, 100); } - render(props: RenderableProps) { + render() { + const props = this.props; // TODO: will be great to `b` to accept `string | undefined | (string|undefined)[]` as classname let className = b('auth-panel-anonymous-login-form', {}, { theme: props.theme }); if (props.className) { @@ -77,7 +78,7 @@ export class AnonymousLoginForm extends Component {
(this.inputRef = ref)} + ref={this.inputRef} type="text" placeholder="Username" value={this.state.inputValue} diff --git a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx index 55c9926a..a8db5efe 100644 --- a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx +++ b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.test.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h } from 'preact'; +/** @jsx createElement */ +import { createElement } from 'preact'; import { mount } from 'enzyme'; import { EmailLoginForm, Props, State } from './auth-panel__email-login-form'; import { User } from '@app/common/types'; diff --git a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx index 544e4b3a..1d4bb7ad 100644 --- a/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx +++ b/frontend/app/components/auth-panel/__email-login-form/auth-panel__email-login-form.tsx @@ -1,10 +1,11 @@ -/** @jsx h */ -import { h, Component, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, Component, createRef } from 'preact'; +import { forwardRef } from 'preact/compat'; import b from 'bem-react-helper'; +import { useSelector } from 'react-redux'; import { Theme, User } from '@app/common/types'; import { sendEmailVerificationRequest } from '@app/common/api'; import { extractErrorMessageFromResponse } from '@app/utils/errorUtils'; -import { connect } from 'preact-redux'; import { getHandleClickProps } from '@app/common/accessibility'; import { sleep } from '@app/utils/sleep'; import TextareaAutosize from '@app/components/input/textarea-autosize'; @@ -13,12 +14,14 @@ const mapStateToProps = () => ({ sendEmailVerification: sendEmailVerificationRequest, }); -export type Props = { +interface OwnProps { onSignIn(token: string): Promise; onSuccess?(user: User): Promise; theme: Theme; className?: string; -} & ReturnType; +} + +export type Props = OwnProps & ReturnType; export interface State { usernameValue: string; @@ -33,8 +36,8 @@ export class EmailLoginForm extends Component { static usernameRegex = /^[a-zA-Z][\w ]+$/; static emailRegex = /[^@]+@[^.]+\..+/; - inputRef?: HTMLInputElement; - tokenRef?: TextareaAutosize; + inputRef = createRef(); + tokenRef = createRef(); constructor(props: Props) { super(props); @@ -59,11 +62,11 @@ export class EmailLoginForm extends Component { async focus() { await sleep(100); - if (this.inputRef) { - this.inputRef.focus(); + if (this.inputRef.current) { + this.inputRef.current.focus(); return; } - this.tokenRef && this.tokenRef.textareaRef && this.tokenRef.textareaRef.select(); + this.tokenRef.current && this.tokenRef.current.textareaRef && this.tokenRef.current.textareaRef.select(); } async onVerificationSubmit(e: Event) { @@ -73,7 +76,7 @@ export class EmailLoginForm extends Component { await this.props.sendEmailVerification(this.state.usernameValue, this.state.addressValue); this.setState({ verificationSent: true }); setTimeout(() => { - this.tokenRef && this.tokenRef.focus(); + this.tokenRef.current && this.tokenRef.current.focus(); }, 100); } catch (e) { this.setState({ error: extractErrorMessageFromResponse(e) }); @@ -119,7 +122,7 @@ export class EmailLoginForm extends Component { verificationSent: false, }); setTimeout(() => { - this.inputRef && this.inputRef.focus(); + this.inputRef.current && this.inputRef.current.focus(); }, 100); } @@ -141,11 +144,11 @@ export class EmailLoginForm extends Component { componentDidMount() { setTimeout(() => { - this.inputRef && this.inputRef.focus(); + this.inputRef.current && this.inputRef.current.focus(); }, 100); } - render(props: RenderableProps) { + render(props: Props) { // TODO: will be great to `b` to accept `string | undefined | (string|undefined)[]` as classname let className = b('auth-panel-email-login-form', {}, { theme: props.theme }); if (props.className) { @@ -173,7 +176,7 @@ export class EmailLoginForm extends Component { (this.inputRef = ref)} + ref={this.inputRef} type="text" placeholder="Username" value={this.state.usernameValue} @@ -193,7 +196,7 @@ export class EmailLoginForm extends Component { title={form1InvalidReason || ''} disabled={form1InvalidReason !== null} /> - {this.state.error && } + {this.state.error &&
{this.state.error}
} ); @@ -207,7 +210,7 @@ export class EmailLoginForm extends Component { (this.tokenRef = ref)} + ref={this.tokenRef} placeholder="Token" value={this.state.tokenValue} onInput={this.onTokenChange} @@ -221,15 +224,15 @@ export class EmailLoginForm extends Component { title={form2InvalidReason || ''} disabled={form2InvalidReason !== null} /> - {this.state.error && } + {this.state.error &&
{this.state.error}
} ); } } -export const EmailLoginFormConnected = connect( - mapStateToProps, - null, - null, - { withRef: true } -)(EmailLoginForm); +export type EmailLoginFormRef = EmailLoginForm; + +export const EmailLoginFormConnected = forwardRef((props, ref) => { + const connectedProps = useSelector(mapStateToProps); + return ; +}); diff --git a/frontend/app/components/auth-panel/__user-id/auth-panel__user-id.tsx b/frontend/app/components/auth-panel/__user-id/auth-panel__user-id.tsx index 9eb97bcc..60962192 100644 --- a/frontend/app/components/auth-panel/__user-id/auth-panel__user-id.tsx +++ b/frontend/app/components/auth-panel/__user-id/auth-panel__user-id.tsx @@ -1,20 +1,15 @@ -/** @jsx h */ -import { h } from 'preact'; +/** @jsx createElement */ +import { createElement, JSX, FunctionComponent } from 'preact'; import b from 'bem-react-helper'; import { Theme } from '@app/common/types'; -import { exclude } from '@app/utils/exclude'; -interface Props { +type Props = { id: string; theme: Theme; -} +} & JSX.HTMLAttributes; -export const UserID = (props: JSX.HTMLAttributes & Props) => ( -
- {props.id} +export const UserID: FunctionComponent = ({ id, theme, ...props }) => ( +
+ {id}
); diff --git a/frontend/app/components/auth-panel/auth-panel.test.tsx b/frontend/app/components/auth-panel/auth-panel.test.tsx index 07c0de00..f0712e3d 100644 --- a/frontend/app/components/auth-panel/auth-panel.test.tsx +++ b/frontend/app/components/auth-panel/auth-panel.test.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h } from 'preact'; +/** @jsx createElement */ +import { createElement } from 'preact'; import { mount } from 'enzyme'; import { Props, AuthPanel } from './auth-panel'; import { User, PostInfo } from '../../common/types'; diff --git a/frontend/app/components/auth-panel/auth-panel.tsx b/frontend/app/components/auth-panel/auth-panel.tsx index 0ed6d820..94181689 100644 --- a/frontend/app/components/auth-panel/auth-panel.tsx +++ b/frontend/app/components/auth-panel/auth-panel.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h, Component, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, Component, createRef } from 'preact'; import b from 'bem-react-helper'; import { PROVIDER_NAMES, IS_STORAGE_AVAILABLE, IS_THIRD_PARTY } from '@app/common/constants'; @@ -11,11 +11,12 @@ import Dropdown, { DropdownItem } from '@app/components/dropdown'; import { Button } from '@app/components/button'; import { UserID } from './__user-id'; import { AnonymousLoginForm } from './__anonymous-login-form'; -import { EmailLoginForm, EmailLoginFormConnected } from './__email-login-form'; +import { EmailLoginFormConnected } from './__email-login-form'; import { StoreState } from '@app/store'; import { ProviderState } from '@app/store/provider/reducers'; import debounce from '@app/utils/debounce'; import postMessage from '@app/utils/postMessage'; +import { EmailLoginFormRef } from './__email-login-form/auth-panel__email-login-form'; export interface Props { user: User | null; @@ -44,7 +45,7 @@ interface State { } export class AuthPanel extends Component { - emailLoginRef?: EmailLoginForm; + emailLoginRef = createRef(); constructor(props: Props) { super(props); @@ -85,7 +86,7 @@ export class AuthPanel extends Component { }, 100); onEmailTitleClick() { - this.emailLoginRef && this.emailLoginRef.focus(); + this.emailLoginRef.current && this.emailLoginRef.current.focus(); } onSortChange(e: Event) { @@ -208,7 +209,7 @@ export class AuthPanel extends Component { > (this.emailLoginRef = ref ? ref.getWrappedInstance() : null)} + ref={this.emailLoginRef} onSignIn={this.onEmailSignIn} theme={this.props.theme} className="auth-panel__email-login-form" @@ -305,7 +306,7 @@ export class AuthPanel extends Component {
Disable third-party cookies blocking to sign in or open comments in{' '} @@ -373,7 +374,7 @@ export class AuthPanel extends Component { ); }; - render(props: RenderableProps, { isBlockedVisible }: State) { + render(props: Props, { isBlockedVisible }: State) { const { user, postInfo: { read_only }, diff --git a/frontend/app/components/avatar-icon/avatar-icon.tsx b/frontend/app/components/avatar-icon/avatar-icon.tsx index 2802d8cf..c11635b9 100644 --- a/frontend/app/components/avatar-icon/avatar-icon.tsx +++ b/frontend/app/components/avatar-icon/avatar-icon.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h } from 'preact'; +/** @jsx createElement */ +import { createElement, JSX } from 'preact'; import b from 'bem-react-helper'; import { Theme } from '@app/common/types'; diff --git a/frontend/app/components/button/button.tsx b/frontend/app/components/button/button.tsx index a82a7474..cbff6e06 100644 --- a/frontend/app/components/button/button.tsx +++ b/frontend/app/components/button/button.tsx @@ -1,11 +1,11 @@ -/** @jsx h */ -import { Component, h, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, JSX, Component } from 'preact'; import b from 'bem-react-helper'; import noop from '@app/utils/noop'; import { Theme } from '@app/common/types'; -interface Props { +type Props = { type?: string; kind?: string; theme: Theme; @@ -14,14 +14,14 @@ interface Props { onClick?: (e: MouseEvent) => void; onFocus?: (e: FocusEvent) => void; onBlur?: (e: FocusEvent) => void; -} +} & JSX.HTMLAttributes; interface State { isClicked: boolean; isFocused: boolean; } -export class Button extends Component { +export class Button extends Component { constructor(props: Props) { super(props); @@ -62,7 +62,7 @@ export class Button extends Component { this.props.onFocus!(e); } - render(props: RenderableProps, state: State) { + render(props: Props, state: State) { const { children, className } = props; const { isClicked, isFocused } = state; diff --git a/frontend/app/components/comment/comment.test.tsx b/frontend/app/components/comment/comment.test.tsx index 7f86b714..d6ae81dd 100644 --- a/frontend/app/components/comment/comment.test.tsx +++ b/frontend/app/components/comment/comment.test.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h } from 'preact'; +/** @jsx createElement */ +import { createElement } from 'preact'; import { mount } from 'enzyme'; import { Props, Comment } from './comment'; import { User, Comment as CommentType, PostInfo } from '@app/common/types'; diff --git a/frontend/app/components/comment/comment.tsx b/frontend/app/components/comment/comment.tsx index 2fe104c2..a252a288 100644 --- a/frontend/app/components/comment/comment.tsx +++ b/frontend/app/components/comment/comment.tsx @@ -1,8 +1,8 @@ -/** @jsx h */ +/** @jsx createElement */ import './styles'; -import { h, Component, RenderableProps } from 'preact'; +import { createElement, JSX, Component, createRef } from 'preact'; import b from 'bem-react-helper'; import { getHandleClickProps } from '@app/common/accessibility'; @@ -72,7 +72,7 @@ export interface State { export class Comment extends Component { votingPromise: Promise; /** comment text node. Used in comment text copying */ - textNode?: HTMLDivElement; + textNode = createRef(); constructor(props: Props) { super(props); @@ -305,7 +305,7 @@ export class Comment extends Component { copyComment = () => { const username = this.props.data.user.name; const time = this.props.data.time; - const text = this.textNode!.textContent || ''; + const text = this.textNode.current!.textContent || ''; copy(`${username} ${time}
${text.replace(/\n+/g, '
')}`); @@ -447,7 +447,7 @@ export class Comment extends Component { return controls; }; - render(props: RenderableProps, state: State) { + render(props: Props, state: State) { const isAdmin = this.isAdmin(); const isGuest = this.isGuest(); const isCurrentUser = this.isCurrentUser(); @@ -547,7 +547,9 @@ export class Comment extends Component { } if (!props.editMode && this.props.inView === false) { - const [width, height] = this.base ? [this.base.scrollWidth, this.base.scrollHeight] : [100, 100]; + const [width, height] = this.base + ? [(this.base as Element).scrollWidth, (this.base as Element).scrollHeight] + : [100, 100]; return (
{ {(!props.collapsed || props.view === 'pinned') && (
(this.textNode = r)} + ref={this.textNode} dangerouslySetInnerHTML={{ __html: o.text }} /> )} diff --git a/frontend/app/components/comment/connected-comment.ts b/frontend/app/components/comment/connected-comment.tsx similarity index 64% rename from frontend/app/components/comment/connected-comment.ts rename to frontend/app/components/comment/connected-comment.tsx index 994288b3..ebc79da4 100644 --- a/frontend/app/components/comment/connected-comment.ts +++ b/frontend/app/components/comment/connected-comment.tsx @@ -3,11 +3,15 @@ * and should be importded explicitly */ +/** @jsx createElement */ + import './styles'; +import { createElement, FunctionComponent } from 'preact'; + import { Comment as CommentType } from '@app/common/types'; -import { connect } from 'preact-redux'; +import { useStore } from 'react-redux'; import { StoreState } from '@app/store'; import { @@ -26,27 +30,30 @@ import { getCommentMode } from '@app/store/comments/getters'; import { uploadImage, getPreview } from '@app/common/api'; import { getThreadIsCollapsed } from '@app/store/thread/getters'; import { bindActions } from '@app/utils/actionBinder'; +import { useActions } from '@app/hooks/useAction'; + +type ProvidedProps = Pick< + Props, + | 'editMode' + | 'user' + | 'isUserBanned' + | 'post_info' + | 'isCommentsDisabled' + | 'theme' + | 'collapsed' + | 'getPreview' + | 'uploadImage' +>; const mapStateToProps = (state: StoreState, cprops: { data: CommentType }) => { - const props: Pick< - Props, - | 'editMode' - | 'user' - | 'isUserBanned' - | 'post_info' - | 'isCommentsDisabled' - | 'theme' - | 'collapsed' - | 'getPreview' - | 'uploadImage' - > = { - editMode: getCommentMode(state, cprops.data.id), + const props: ProvidedProps = { + editMode: getCommentMode(cprops.data.id)(state), user: state.user, isUserBanned: cprops.data.user.block || state.bannedUsers.find(u => u.id === cprops.data.user.id) !== undefined, post_info: state.info, isCommentsDisabled: state.info.read_only || false, theme: state.theme, - collapsed: getThreadIsCollapsed(state, cprops.data), + collapsed: getThreadIsCollapsed(cprops.data)(state), getPreview, uploadImage, }; @@ -67,8 +74,8 @@ export const boundActions = bindActions({ setVerifyStatus: setVerifiedStatus, }); -/** Comment component connected to redux */ -export const ConnectedComment = connect( - mapStateToProps, - boundActions as Partial -)(Comment); +export const ConnectedComment: FunctionComponent> = props => { + const providedProps = mapStateToProps(useStore().getState(), props); + const actions = useActions(boundActions); + return ; +}; diff --git a/frontend/app/components/countdown/index.tsx b/frontend/app/components/countdown/index.tsx index 518f385f..6a72aec7 100644 --- a/frontend/app/components/countdown/index.tsx +++ b/frontend/app/components/countdown/index.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h, Component, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, JSX, Component, createRef } from 'preact'; import { exclude } from '@app/utils/exclude'; type Props = { @@ -14,7 +14,7 @@ interface State { /** Component which uses plain DOM mutation instead of rerendering react reactive reactivity */ export default class Countdown extends Component { - elemRef?: HTMLSpanElement; + elemRef = createRef(); intervalID?: number; constructor(props: Props) { super(props); @@ -41,7 +41,7 @@ export default class Countdown extends Component { tick() { if (this.elemRef) { const value = Math.max(0, (this.state.time - new Date().getTime()) / 1000).toFixed(0); - this.elemRef!.innerText = value; + this.elemRef.current!.innerText = value; if (value === '0') { this.props.onTimePassed && this.props.onTimePassed(); window.clearInterval(this.intervalID); @@ -56,7 +56,7 @@ export default class Countdown extends Component { this.tick(); }, 1000); } - render(props: RenderableProps) { - return (this.elemRef = ref)} />; + render(props: Props) { + return ; } } diff --git a/frontend/app/components/dropdown/__item/dropdown__item.tsx b/frontend/app/components/dropdown/__item/dropdown__item.tsx index dcacf804..0e008683 100644 --- a/frontend/app/components/dropdown/__item/dropdown__item.tsx +++ b/frontend/app/components/dropdown/__item/dropdown__item.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { h, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, JSX, RenderableProps } from 'preact'; import b from 'bem-react-helper'; interface Props { diff --git a/frontend/app/components/dropdown/dropdown.tsx b/frontend/app/components/dropdown/dropdown.tsx index b4ffdda0..17872368 100644 --- a/frontend/app/components/dropdown/dropdown.tsx +++ b/frontend/app/components/dropdown/dropdown.tsx @@ -1,5 +1,5 @@ -/** @jsx h */ -import { Component, h, RenderableProps } from 'preact'; +/** @jsx createElement */ +import { createElement, Component, createRef } from 'preact'; import b from 'bem-react-helper'; import { Button } from '@app/components/button'; @@ -24,7 +24,7 @@ interface State { } export default class Dropdown extends Component { - rootNode?: HTMLDivElement; + rootNode = createRef(); constructor(props: Props) { super(props); @@ -52,10 +52,10 @@ export default class Dropdown extends Component { await this.__adjustDropDownContent(); if (isActive) { this.__onOpen(); - this.props.onOpen && this.props.onOpen(this.rootNode!); + this.props.onOpen && this.props.onOpen(this.rootNode.current!); } else { this.__onClose(); - this.props.onClose && this.props.onClose(this.rootNode!); + this.props.onClose && this.props.onClose(this.rootNode.current!); } if (this.props.onTitleClick) { @@ -71,8 +71,8 @@ export default class Dropdown extends Component { __onOpen() { const isChildOfDropDown = (() => { - if (!this.rootNode) return false; - let parent = this.rootNode.parentElement!; + if (!this.rootNode.current) return false; + let parent = this.rootNode.current.parentElement!; while (parent !== document.body) { if (parent.classList.contains('dropdown')) return true; parent = parent.parentElement!; @@ -87,10 +87,10 @@ export default class Dropdown extends Component { let prevDcBottom: number | null = null; this.checkInterval = window.setInterval(() => { - if (!this.rootNode || !this.state.isActive) return; + if (!this.rootNode.current || !this.state.isActive) return; const windowHeight = window.innerHeight; const dcBottom = (() => { - const dc = Array.from(this.rootNode.children).find(c => c.classList.contains('dropdown__content')); + const dc = Array.from(this.rootNode.current.children).find(c => c.classList.contains('dropdown__content')); if (!dc) return 0; const rect = dc.getBoundingClientRect(); return window.scrollY + Math.abs(rect.top) + dc.scrollHeight + 10; @@ -111,8 +111,8 @@ export default class Dropdown extends Component { } async __adjustDropDownContent() { - if (!this.rootNode) return; - const dc = this.rootNode.querySelector('.dropdown__content'); + if (!this.rootNode.current) return; + const dc = this.rootNode.current.querySelector('.dropdown__content'); if (!dc) return; await sleep(10); const rect = dc.getBoundingClientRect(); @@ -144,14 +144,14 @@ export default class Dropdown extends Component { }, () => { this.__onClose(); - this.props.onClose && this.props.onClose(this.rootNode!); + this.props.onClose && this.props.onClose(this.rootNode.current!); } ); } catch (e) {} } onOutsideClick(e: MouseEvent) { - if (!this.rootNode || this.rootNode.contains(e.target as Node) || !this.state.isActive) return; + if (!this.rootNode.current || this.rootNode.current.contains(e.target as Node) || !this.state.isActive) return; this.setState( { contentTranslateX: 0, @@ -159,7 +159,7 @@ export default class Dropdown extends Component { }, () => { this.__onClose(); - this.props.onClose && this.props.onClose(this.rootNode!); + this.props.onClose && this.props.onClose(this.rootNode.current!); } ); } @@ -176,11 +176,12 @@ export default class Dropdown extends Component { window.removeEventListener('message', this.receiveMessage); } - render(props: RenderableProps, { isActive }: State) { - const { title, titleClass, heading, children, mix } = props; + render() { + const { title, titleClass, heading, children, mix, theme } = this.props; + const { isActive } = this.state; return ( -
(this.rootNode = r)}> +