From 723d9f46df9d82c5d13c78daf6c99471e05decb9 Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Mon, 1 Jul 2019 09:56:31 +0200 Subject: [PATCH 01/14] update eslint components --- client/package.json | 12 +-- client/yarn.lock | 215 +++++++++++++++++++++----------------------- 2 files changed, 109 insertions(+), 118 deletions(-) diff --git a/client/package.json b/client/package.json index 616d660a8..3414c1255 100644 --- a/client/package.json +++ b/client/package.json @@ -56,19 +56,19 @@ "@babel/preset-react": "^7.0.0", "@fortawesome/fontawesome-free": "^5.5.0", "autoprefixer": "7.1.5", - "babel-eslint": "8.2.1", + "babel-eslint": "10.0.2", "babel-jest": "24.8.0", "babel-loader": "^8.0.0", "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.26.0", "clean-webpack-plugin": "0.1.17", "css-loader": "2.1.1", - "eslint": "5.16.0", - "eslint-config-airbnb": "16.1.0", + "eslint": "6.0.1", + "eslint-config-airbnb": "17.1.0", "eslint-loader": "2.1.2", - "eslint-plugin-import": "2.17.3", - "eslint-plugin-jsx-a11y": "6.2.1", - "eslint-plugin-react": "7.13.0", + "eslint-plugin-import": "2.18.0", + "eslint-plugin-jsx-a11y": "6.2.3", + "eslint-plugin-react": "7.14.2", "express": "4.16.4", "file-loader": "1.1.11", "html-webpack-plugin": "3.2.0", diff --git a/client/yarn.lock b/client/yarn.lock index 5ded5422f..3de308ac6 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -18,14 +18,6 @@ optionalDependencies: chokidar "^2.0.3" -"@babel/code-frame@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.36.tgz#2349d7ec04b3a06945ae173280ef8579b63728e4" - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - "@babel/code-frame@7.0.0-beta.46": version "7.0.0-beta.46" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.46.tgz#e0d002100805daab1461c0fcb32a07e304f3a4f4" @@ -180,14 +172,6 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-function-name@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.36.tgz#366e3bc35147721b69009f803907c4d53212e88d" - dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.36" - "@babel/template" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - "@babel/helper-function-name@7.0.0-beta.46": version "7.0.0-beta.46" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.46.tgz#d0c4eed2e220e180f91b02e008dcc4594afe1d39" @@ -204,12 +188,6 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-get-function-arity@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.36.tgz#f5383bac9a96b274828b10d98900e84ee43e32b8" - dependencies: - "@babel/types" "7.0.0-beta.36" - "@babel/helper-get-function-arity@7.0.0-beta.46": version "7.0.0-beta.46" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.46.tgz#7161bfe449b4183dbe25d1fe5579338b7429e5f2" @@ -735,14 +713,12 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/template@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.36.tgz#02e903de5d68bd7899bce3c5b5447e59529abb00" +"@babel/runtime@^7.4.5": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12" + integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ== dependencies: - "@babel/code-frame" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - babylon "7.0.0-beta.36" - lodash "^4.2.0" + regenerator-runtime "^0.13.2" "@babel/template@7.0.0-beta.46": version "7.0.0-beta.46" @@ -769,19 +745,6 @@ "@babel/parser" "^7.2.2" "@babel/types" "^7.2.2" -"@babel/traverse@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.36.tgz#1dc6f8750e89b6b979de5fe44aa993b1a2192261" - dependencies: - "@babel/code-frame" "7.0.0-beta.36" - "@babel/helper-function-name" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - babylon "7.0.0-beta.36" - debug "^3.0.1" - globals "^11.1.0" - invariant "^2.2.0" - lodash "^4.2.0" - "@babel/traverse@7.0.0-beta.46", "@babel/traverse@^7.0.0-beta.42": version "7.0.0-beta.46" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.46.tgz#29a0c0395b3642f0297e6f8e475bde89f9343755" @@ -825,14 +788,6 @@ globals "^11.1.0" lodash "^4.17.11" -"@babel/types@7.0.0-beta.36": - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.36.tgz#64f2004353de42adb72f9ebb4665fc35b5499d23" - dependencies: - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^2.0.0" - "@babel/types@7.0.0-beta.46": version "7.0.0-beta.46" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.46.tgz#eb84399a699af9fcb244440cce78e1acbeb40e0c" @@ -1204,7 +1159,7 @@ ajv@^5.0.0, ajv@^5.2.3: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.1.0, ajv@^6.5.5, ajv@^6.9.1: +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.5.5, ajv@^6.9.1: version "6.10.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" dependencies: @@ -1475,15 +1430,16 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-eslint@8.2.1: - version "8.2.1" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.1.tgz#136888f3c109edc65376c23ebf494f36a3e03951" +babel-eslint@10.0.2: + version "10.0.2" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.2.tgz#182d5ac204579ff0881684b040560fdcc1558456" + integrity sha512-UdsurWPtgiPgpJ06ryUnuaSXC2s0WoSZnQmEpbAH65XZSdwowgN5MvyP7e88nW07FYXv72erVtpBkxyDVKhH1Q== dependencies: - "@babel/code-frame" "7.0.0-beta.36" - "@babel/traverse" "7.0.0-beta.36" - "@babel/types" "7.0.0-beta.36" - babylon "7.0.0-beta.36" - eslint-scope "~3.7.1" + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" + eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" babel-helper-function-name@^6.24.1: @@ -1640,10 +1596,6 @@ babel-types@^6.24.1, babel-types@^6.26.0: lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@7.0.0-beta.36: - version "7.0.0-beta.36" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.36.tgz#3a3683ba6a9a1e02b0aa507c8e63435e39305b9e" - babylon@7.0.0-beta.46, babylon@^7.0.0-beta.42: version "7.0.0-beta.46" resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.46.tgz#b6ddaba81bbb130313932757ff9c195d527088b6" @@ -2656,7 +2608,7 @@ debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6. dependencies: ms "2.0.0" -debug@3.1.0, debug@^3.0.0, debug@^3.0.1, debug@^3.1.0: +debug@3.1.0, debug@^3.0.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2702,6 +2654,13 @@ define-properties@^1.1.2: foreach "^2.0.5" object-keys "^1.0.8" +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -2995,7 +2954,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.11.0, es-abstract@^1.5.1: +es-abstract@^1.11.0, es-abstract@^1.12.0, es-abstract@^1.5.1: version "1.13.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" dependencies: @@ -3113,17 +3072,23 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-config-airbnb-base@^12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944" +eslint-config-airbnb-base@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" + integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw== dependencies: eslint-restricted-globals "^0.1.1" + object.assign "^4.1.0" + object.entries "^1.0.4" -eslint-config-airbnb@16.1.0: - version "16.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz#2546bfb02cc9fe92284bf1723ccf2e87bc45ca46" +eslint-config-airbnb@17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" + integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw== dependencies: - eslint-config-airbnb-base "^12.1.0" + eslint-config-airbnb-base "^13.1.0" + object.assign "^4.1.0" + object.entries "^1.0.4" eslint-import-resolver-node@^0.3.2: version "0.3.2" @@ -3151,10 +3116,10 @@ eslint-module-utils@^2.4.0: debug "^2.6.8" pkg-dir "^2.0.0" -eslint-plugin-import@2.17.3: - version "2.17.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.3.tgz#00548b4434c18faebaba04b24ae6198f280de189" - integrity sha512-qeVf/UwXFJbeyLbxuY8RgqDyEKCkqV7YC+E5S5uOjAp4tOc8zj01JP3ucoBM8JcEqd1qRasJSg6LLlisirfy0Q== +eslint-plugin-import@2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.0.tgz#7a5ba8d32622fb35eb9c8db195c2090bd18a3678" + integrity sha512-PZpAEC4gj/6DEMMoU2Df01C5c50r7zdGIN52Yfi7CvvWaYssG7Jt5R9nFG5gmqodxNOz9vQS87xk6Izdtpdrig== dependencies: array-includes "^3.0.3" contains-path "^0.1.0" @@ -3168,11 +3133,12 @@ eslint-plugin-import@2.17.3: read-pkg-up "^2.0.0" resolve "^1.11.0" -eslint-plugin-jsx-a11y@6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz#4ebba9f339b600ff415ae4166e3e2e008831cf0c" - integrity sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w== +eslint-plugin-jsx-a11y@6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" + integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== dependencies: + "@babel/runtime" "^7.4.5" aria-query "^3.0.0" array-includes "^3.0.3" ast-types-flow "^0.0.7" @@ -3180,18 +3146,20 @@ eslint-plugin-jsx-a11y@6.2.1: damerau-levenshtein "^1.0.4" emoji-regex "^7.0.2" has "^1.0.3" - jsx-ast-utils "^2.0.1" + jsx-ast-utils "^2.2.1" -eslint-plugin-react@7.13.0: - version "7.13.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.13.0.tgz#bc13fd7101de67996ea51b33873cd9dc2b7e5758" - integrity sha512-uA5LrHylu8lW/eAH3bEQe9YdzpPaFd9yAJTwTi/i/BKTD7j6aQMKVAdGM/ML72zD6womuSK7EiGtMKuK06lWjQ== +eslint-plugin-react@7.14.2: + version "7.14.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.2.tgz#94c193cc77a899ac0ecbb2766fbef88685b7ecc1" + integrity sha512-jZdnKe3ip7FQOdjxks9XPN0pjUKZYq48OggNMd16Sk+8VXx6JOvXmlElxROCgp7tiUsTsze3jd78s/9AFJP2mA== dependencies: array-includes "^3.0.3" doctrine "^2.1.0" has "^1.0.3" jsx-ast-utils "^2.1.0" + object.entries "^1.1.0" object.fromentries "^2.0.0" + object.values "^1.1.0" prop-types "^15.7.2" resolve "^1.10.1" @@ -3199,9 +3167,10 @@ eslint-restricted-globals@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" -eslint-scope@^3.7.1: +eslint-scope@3.7.1, eslint-scope@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3213,13 +3182,6 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@~3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-utils@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" @@ -3228,12 +3190,13 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@5.16.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" +eslint@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.0.1.tgz#4a32181d72cb999d6f54151df7d337131f81cda7" + integrity sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w== dependencies: "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" + ajv "^6.10.0" chalk "^2.1.0" cross-spawn "^6.0.5" debug "^4.0.1" @@ -3241,18 +3204,19 @@ eslint@5.16.0: eslint-scope "^4.0.3" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" - espree "^5.0.1" + espree "^6.0.0" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" - glob "^7.1.2" + glob-parent "^3.1.0" globals "^11.7.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" inquirer "^6.2.2" - js-yaml "^3.13.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" lodash "^4.17.11" @@ -3260,7 +3224,6 @@ eslint@5.16.0: mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" - path-is-inside "^1.0.2" progress "^2.0.0" regexpp "^2.0.1" semver "^5.5.1" @@ -3314,9 +3277,10 @@ espree@^3.1.6: acorn "^5.5.0" acorn-jsx "^3.0.0" -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" +espree@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6" + integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q== dependencies: acorn "^6.0.7" acorn-jsx "^5.0.0" @@ -5311,7 +5275,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" -js-yaml@^3.13.0, js-yaml@^3.13.1: +js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" dependencies: @@ -5441,12 +5405,6 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsx-ast-utils@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" - dependencies: - array-includes "^3.0.3" - jsx-ast-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz#0ee4e2c971fb9601c67b5641b71be80faecf0b36" @@ -5454,6 +5412,14 @@ jsx-ast-utils@^2.1.0: dependencies: array-includes "^3.0.3" +jsx-ast-utils@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz#4d4973ebf8b9d2837ee91a8208cc66f3a2776cfb" + integrity sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ== + dependencies: + array-includes "^3.0.3" + object.assign "^4.1.0" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -6372,6 +6338,16 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.entries@^1.0.4, object.entries@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" + integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + object.fromentries@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab" @@ -6402,6 +6378,16 @@ object.pick@^1.3.0: dependencies: isobject "^3.0.1" +object.values@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" + integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -6642,7 +6628,7 @@ path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1, path-is-inside@^1.0.2: +path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -7521,6 +7507,11 @@ regenerator-runtime@^0.12.0: version "0.12.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" +regenerator-runtime@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" + integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== + regenerator-transform@^0.13.4: version "0.13.4" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" From a494f009642aaeca5643823f1cc83a96e814e5b0 Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Mon, 1 Jul 2019 09:57:02 +0200 Subject: [PATCH 02/14] run 'eslint app server.js --fix' --- client/app/scripts/charts/edge-container.js | 11 +++-- .../scripts/charts/nodes-chart-elements.js | 12 ++--- client/app/scripts/charts/nodes-grid.js | 13 +++--- client/app/scripts/charts/nodes-layout.js | 2 +- client/app/scripts/components/app.js | 10 +++-- .../app/scripts/components/debug-toolbar.js | 10 +++-- .../scripts/components/embedded-terminal.js | 6 +-- client/app/scripts/components/footer.js | 8 +++- client/app/scripts/components/help-panel.js | 38 +++++++++++++--- .../app/scripts/components/matched-results.js | 7 ++- .../app/scripts/components/metric-selector.js | 4 +- client/app/scripts/components/node-details.js | 45 +++++++++++++------ .../__tests__/node-details-table-test.js | 3 +- .../node-details/node-details-controls.js | 4 +- .../node-details-generic-table.js | 23 +++++----- .../node-details/node-details-health.js | 24 +++++----- .../node-details/node-details-info.js | 28 +++++++----- .../node-details-property-list.js | 10 +++-- .../node-details/node-details-relatives.js | 7 ++- .../node-details-table-headers.js | 5 +-- .../node-details/node-details-table-row.js | 30 +++++++------ .../node-details/node-details-table.js | 16 ++++--- .../nodes-resources/node-resources-layer.js | 6 ++- .../node-resources-metric-box-info.js | 16 +++++-- .../node-resources-metric-box.js | 30 +++++++++---- client/app/scripts/components/nodes.js | 8 ++-- client/app/scripts/components/plugins.js | 11 ++++- client/app/scripts/components/search.js | 8 +++- client/app/scripts/components/show-more.js | 4 +- client/app/scripts/components/sparkline.js | 10 +++-- client/app/scripts/components/terminal-app.js | 6 ++- client/app/scripts/components/terminal.js | 8 ++-- client/app/scripts/components/time-control.js | 8 +++- .../scripts/components/topology-options.js | 4 +- .../components/troubleshooting-menu.js | 9 +++- .../app/scripts/components/zoomable-canvas.js | 10 +++-- client/app/scripts/decorators/node.js | 6 +-- client/app/scripts/reducers/root.js | 4 +- client/app/scripts/selectors/node-metric.js | 5 +-- .../scripts/selectors/resource-view/layout.js | 13 +++--- client/app/scripts/selectors/search.js | 4 +- .../utils/__tests__/web-api-utils-test.js | 4 +- client/app/scripts/utils/array-utils.js | 3 +- client/app/scripts/utils/hash-utils.js | 4 +- client/app/scripts/utils/metric-utils.js | 6 +-- client/app/scripts/utils/router-utils.js | 4 +- client/app/scripts/utils/topology-utils.js | 6 +-- client/app/scripts/utils/web-api-utils.js | 6 +-- 48 files changed, 336 insertions(+), 183 deletions(-) diff --git a/client/app/scripts/charts/edge-container.js b/client/app/scripts/charts/edge-container.js index 2ad0f8199..9d357d945 100644 --- a/client/app/scripts/charts/edge-container.js +++ b/client/app/scripts/charts/edge-container.js @@ -88,12 +88,11 @@ export default class EdgeContainer extends React.PureComponent { ...waypointsMap.toJS(), }}> { - ({ interpolatedThickness, ...interpolatedWaypoints }) => - transformedEdge( - forwardedProps, - waypointsMapToArray(fromJS(interpolatedWaypoints)), - interpolatedThickness - ) + ({ interpolatedThickness, ...interpolatedWaypoints }) => transformedEdge( + forwardedProps, + waypointsMapToArray(fromJS(interpolatedWaypoints)), + interpolatedThickness + ) } ); diff --git a/client/app/scripts/charts/nodes-chart-elements.js b/client/app/scripts/charts/nodes-chart-elements.js index 52c3e3b1f..741fbb9d4 100644 --- a/client/app/scripts/charts/nodes-chart-elements.js +++ b/client/app/scripts/charts/nodes-chart-elements.js @@ -63,9 +63,9 @@ class NodesChartElements extends React.Component { nodeDisplayLayer(node) { if (node.get('id') === this.props.mouseOverNodeId) { return HOVERED_NODES_LAYER; - } else if (node.get('blurred') && !node.get('focused')) { + } if (node.get('blurred') && !node.get('focused')) { return BLURRED_NODES_LAYER; - } else if (node.get('highlighted')) { + } if (node.get('highlighted')) { return HIGHLIGHTED_NODES_LAYER; } return NORMAL_NODES_LAYER; @@ -74,9 +74,9 @@ class NodesChartElements extends React.Component { edgeDisplayLayer(edge) { if (edge.get('id') === this.props.mouseOverEdgeId) { return HOVERED_EDGES_LAYER; - } else if (edge.get('blurred') && !edge.get('focused')) { + } if (edge.get('blurred') && !edge.get('focused')) { return BLURRED_EDGES_LAYER; - } else if (edge.get('highlighted')) { + } if (edge.get('highlighted')) { return HIGHLIGHTED_EDGES_LAYER; } return NORMAL_EDGES_LAYER; @@ -140,8 +140,8 @@ class NodesChartElements extends React.Component { const sourceInNetwork = selectedNetworkNodesIds.contains(edge.get('source')); const targetInNetwork = selectedNetworkNodesIds.contains(edge.get('target')); const notInNetwork = this.props.selectedNetwork && (!sourceInNetwork || !targetInNetwork); - return edge.set('blurred', !edge.get('highlighted') && !edge.get('focused') && - (otherNodesSelected || notMatched || notInNetwork)); + return edge.set('blurred', !edge.get('highlighted') && !edge.get('focused') + && (otherNodesSelected || notMatched || notInNetwork)); } edgeScaleDecorator(edge) { diff --git a/client/app/scripts/charts/nodes-grid.js b/client/app/scripts/charts/nodes-grid.js index ffaa8126a..1ee6a64bf 100644 --- a/client/app/scripts/charts/nodes-grid.js +++ b/client/app/scripts/charts/nodes-grid.js @@ -91,7 +91,9 @@ function renderIdCell({
- {label} {showSubLabel && {labelMinor}} + {label} + {' '} + {showSubLabel && {labelMinor}}
); @@ -126,8 +128,7 @@ class NodesGrid extends React.Component { const { nodes, gridSortedBy, gridSortedDesc, searchNodeMatches, searchQuery, windowHeight, topologies } = this.props; - const height = - this.tableRef ? windowHeight - this.tableRef.getBoundingClientRect().top - 30 : 0; + const height = this.tableRef ? windowHeight - this.tableRef.getBoundingClientRect().top - 30 : 0; const cmpStyle = { height, paddingLeft: 40, @@ -152,7 +153,8 @@ class NodesGrid extends React.Component { return (
- {nodes.size > 0 && 0 && ( + } + /> + )}
); } diff --git a/client/app/scripts/charts/nodes-layout.js b/client/app/scripts/charts/nodes-layout.js index 2d0d7321c..cf7ed85bd 100644 --- a/client/app/scripts/charts/nodes-layout.js +++ b/client/app/scripts/charts/nodes-layout.js @@ -408,7 +408,7 @@ function copyLayoutProperties(layout, nodeCache, edgeCache) { if (edgeCache.has(edge.get('id')) && hasSameEndpoints(edgeCache.get(edge.get('id')), result.nodes)) { return edge.merge(edgeCache.get(edge.get('id'))); - } else if (nodeCache.get(edge.get('source')) && nodeCache.get(edge.get('target'))) { + } if (nodeCache.get(edge.get('source')) && nodeCache.get(edge.get('target'))) { return setSimpleEdgePoints(edge, nodeCache); } return edge; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 0b616cfc6..32abc25d5 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -210,19 +210,23 @@ class App extends React.Component { {showingTroubleshootingMenu && } - {showingDetails &&
} + /> + )}
{timeTravelSupported && this.props.renderTimeTravel()}
- {!isIframe && + {!isIframe + && ( + ) }
diff --git a/client/app/scripts/components/debug-toolbar.js b/client/app/scripts/components/debug-toolbar.js index fa71ffb80..6145a57e3 100644 --- a/client/app/scripts/components/debug-toolbar.js +++ b/client/app/scripts/components/debug-toolbar.js @@ -1,7 +1,9 @@ /* eslint react/jsx-no-bind: "off" */ import React from 'react'; import { connect } from 'react-redux'; -import { sampleSize, sample, random, range, flattenDeep, times } from 'lodash'; +import { + sampleSize, sample, random, range, flattenDeep, times +} from 'lodash'; import { fromJS, Set as makeSet } from 'immutable'; import { hsl } from 'd3-color'; import debug from 'debug'; @@ -311,7 +313,8 @@ class DebugToolbar extends React.Component {
- {this.state.showColors && + {this.state.showColors + && ( {LABEL_PREFIXES.map(r => ( @@ -322,7 +325,8 @@ class DebugToolbar extends React.Component { ))} -
} + + )} {this.state.showColors && [getNodeColor, getNodeColorDark].map(fn => ( diff --git a/client/app/scripts/components/embedded-terminal.js b/client/app/scripts/components/embedded-terminal.js index 734a3c2bc..37188e196 100644 --- a/client/app/scripts/components/embedded-terminal.js +++ b/client/app/scripts/components/embedded-terminal.js @@ -31,8 +31,8 @@ class EmeddedTerminal extends React.Component { } getTransform() { - const dx = this.state.mounted ? 0 : - window.innerWidth - DETAILS_PANEL_WIDTH - DETAILS_PANEL_MARGINS.right; + const dx = this.state.mounted ? 0 + : window.innerWidth - DETAILS_PANEL_WIDTH - DETAILS_PANEL_MARGINS.right; return `translateX(${dx}px)`; } @@ -56,7 +56,7 @@ class EmeddedTerminal extends React.Component {
+ style={{transform: this.getTransform()}}>
- {versionUpdate && + {versionUpdate + && ( - Update available: {versionUpdate.get('version')} + Update available: + {' '} + {versionUpdate.get('version')} + ) } Version {version || '...'} diff --git a/client/app/scripts/components/help-panel.js b/client/app/scripts/components/help-panel.js index 445b8a4a4..63cb44910 100644 --- a/client/app/scripts/components/help-panel.js +++ b/client/app/scripts/components/help-panel.js @@ -53,7 +53,12 @@ function renderShortcutPanel() { const BASIC_SEARCHES = [ {label: 'All fields for foo', term: 'foo'}, { - label: Any field matching pid for the value 12345, + label: +Any field matching + pid + {' '} +for the value 12345 + , term: 'pid: 12345' }, ]; @@ -65,16 +70,31 @@ const REGEX_SEARCHES = [ term: 'foo|bar' }, { - label: command field for foobar or foobaz, + label: + command + {' '} +field for foobar or foobaz + , term: 'command: foo(bar|baz)' }, ]; const METRIC_SEARCHES = [ - {label: CPU greater than 4%, term: 'cpu > 4%'}, { - label: Memory less than 10 megabytes, + label: + CPU + {' '} +greater than 4% + , + term: 'cpu > 4%' + }, + { + label: + Memory + {' '} +less than 10 megabytes + , term: 'memory < 10mb' }, ]; @@ -129,8 +149,14 @@ function renderFieldsPanel(currentTopologyName, searchableFields) {

Fields and Metrics

- Searchable fields and metrics in the
- currently selected {currentTopology} topology: + Searchable fields and metrics in the + {' '} +
+ currently selected + {' '} + {currentTopology} + {' '} +topology:

diff --git a/client/app/scripts/components/matched-results.js b/client/app/scripts/components/matched-results.js index 7817f3f4c..61f265910 100644 --- a/client/app/scripts/components/matched-results.js +++ b/client/app/scripts/components/matched-results.js @@ -7,7 +7,8 @@ const Match = (searchTerms, match) => (
- {match.label}: + {match.label} +: Match(searchTerms, matches.get(fieldId))) } - {moreFieldMatches && + {moreFieldMatches + && (
{`${moreFieldMatches.size} more matches`}
+ ) }
); diff --git a/client/app/scripts/components/metric-selector.js b/client/app/scripts/components/metric-selector.js index bca5589d9..debfb0d5e 100644 --- a/client/app/scripts/components/metric-selector.js +++ b/client/app/scripts/components/metric-selector.js @@ -22,7 +22,8 @@ class MetricSelector extends React.Component { return (
- {hasMetrics && + {hasMetrics + && (
{availableMetrics.map(metric => ( ))}
+ ) }
); diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index 50dc20d1a..bd6f27221 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -56,13 +56,18 @@ class NodeDetails extends React.Component { return (
- {showSwitchTopology && + {showSwitchTopology + && ( - Show in {this.props.topologyId.replace(/-/g, ' ')} + +Show in + {this.props.topologyId.replace(/-/g, ' ')} + + ) }

- {this.props.label} not found! + {this.props.label} + {' '} +not found!

@@ -176,14 +183,17 @@ class NodeDetails extends React.Component {
- {details.parents && } + relatives={details.parents} /> + )}
- {showControls && + {showControls + && (
+ ) }
- {details.metrics && + {details.metrics + && (
Status
+ ) } - {details.metadata && + {details.metadata + && (
Info
+ ) } {details.connections && details.connections.filter(cs => cs.connections.length > 0) @@ -219,7 +234,7 @@ class NodeDetails extends React.Component { nodeIdKey="nodeId" />
- ))} + ))} {details.children && details.children.map(children => (
@@ -233,11 +248,13 @@ class NodeDetails extends React.Component {
{table.label && table.label.length > 0 && table.label} - {table.truncationCount > 0 && + {table.truncationCount > 0 + && ( + ) }
{this.renderTable(table)} @@ -266,7 +283,7 @@ class NodeDetails extends React.Component { matches={nodeMatches.get('tables')} /> ); - } else if (isPropertyList(table)) { + } if (isPropertyList(table)) { return ( { // (that is, first by row and then by column), the indexes we are interested in are of the // form columnIndex + n * columns.length, where n >= 0. Therefore we take only the values // at the index which divided by columns.length gives a reminder columnIndex. - const filteredValues = values.filter((element, index) => - index % columns.length === columnIndex); + const filteredValues = values.filter((element, index) => index % columns.length === columnIndex); // Array comparison expect(filteredValues).toEqual(expectedValues); } diff --git a/client/app/scripts/components/node-details/node-details-controls.js b/client/app/scripts/components/node-details/node-details-controls.js index 41e08794f..ca15e1498 100644 --- a/client/app/scripts/components/node-details/node-details-controls.js +++ b/client/app/scripts/components/node-details/node-details-controls.js @@ -15,11 +15,13 @@ export default function NodeDetailsControls({ return (
- {error && + {error + && (
{error}
+ ) } {sortBy(controls, 'rank').map(control => ( diff --git a/client/app/scripts/components/node-details/node-details-generic-table.js b/client/app/scripts/components/node-details/node-details-generic-table.js index 0b933ef5b..6a92f29f7 100644 --- a/client/app/scripts/components/node-details/node-details-generic-table.js +++ b/client/app/scripts/components/node-details/node-details-generic-table.js @@ -62,8 +62,7 @@ export default class NodeDetailsGenericTable extends React.Component { // If there are rows that would be hidden behind 'show more', keep them // expanded if any of them match the search query; otherwise hide them. if (this.state.limit > 0 && rows.length > this.state.limit) { - const hasHiddenMatch = rows.slice(this.state.limit).some(row => - columns.some(column => matches.has(genericTableEntryKey(row, column)))); + const hasHiddenMatch = rows.slice(this.state.limit).some(row => columns.some(column => matches.has(genericTableEntryKey(row, column)))); if (!hasHiddenMatch) { notShown = rows.length - NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT; rows = rows.slice(0, this.state.limit); @@ -94,15 +93,17 @@ export default class NodeDetailsGenericTable extends React.Component { title={value} key={column.id} style={styles[index]}> - {column.dataType === 'link' ? - - {value} - : - + {column.dataType === 'link' + ? ( + + {value} + + ) + : } ); diff --git a/client/app/scripts/components/node-details/node-details-health.js b/client/app/scripts/components/node-details/node-details-health.js index e73b2b0d5..82b89f063 100644 --- a/client/app/scripts/components/node-details/node-details-health.js +++ b/client/app/scripts/components/node-details/node-details-health.js @@ -38,18 +38,22 @@ export default class NodeDetailsHealth extends React.Component { return (
- {shownWithData.map(item => ())} + {shownWithData.map(item => ( + + ))}
- {shownEmpty.map(item => ())} + {shownEmpty.map(item => ( + + ))}
- {field.dataType === 'link' ? - - {value} - : - + {field.dataType === 'link' + ? ( + + {value} + + ) + : ( + + ) }
diff --git a/client/app/scripts/components/node-details/node-details-property-list.js b/client/app/scripts/components/node-details/node-details-property-list.js index 92a7fbc22..e72f7bf05 100644 --- a/client/app/scripts/components/node-details/node-details-property-list.js +++ b/client/app/scripts/components/node-details/node-details-property-list.js @@ -9,10 +9,12 @@ import ShowMore from '../show-more'; const Controls = controls => (
- {sortBy(controls, 'rank').map(control => ())} + {sortBy(controls, 'rank').map(control => ( + + ))}
); diff --git a/client/app/scripts/components/node-details/node-details-relatives.js b/client/app/scripts/components/node-details/node-details-relatives.js index ec9d6dedf..3e2b83794 100644 --- a/client/app/scripts/components/node-details/node-details-relatives.js +++ b/client/app/scripts/components/node-details/node-details-relatives.js @@ -37,13 +37,16 @@ export default class NodeDetailsRelatives extends React.Component { ))} - {showLimitAction && + {...relative} /> + ))} + {showLimitAction + && ( {limitActionText} + ) }
); diff --git a/client/app/scripts/components/node-details/node-details-table-headers.js b/client/app/scripts/components/node-details/node-details-table-headers.js index 37a4a7779..1fd45527c 100644 --- a/client/app/scripts/components/node-details/node-details-table-headers.js +++ b/client/app/scripts/components/node-details/node-details-table-headers.js @@ -33,9 +33,8 @@ export default class NodeDetailsTableHeaders extends React.Component { } const style = colStyles[index]; - const label = - (style.width === NODE_DETAILS_TABLE_CW.XS && NODE_DETAILS_TABLE_XS_LABEL[header.id]) ? - NODE_DETAILS_TABLE_XS_LABEL[header.id] : header.label; + const label = (style.width === NODE_DETAILS_TABLE_CW.XS && NODE_DETAILS_TABLE_XS_LABEL[header.id]) + ? NODE_DETAILS_TABLE_XS_LABEL[header.id] : header.label; return (
); } @@ -72,13 +75,14 @@ function renderValues(node, columns = [], columnStyles = [], timestamp = null, t title={field.value} style={style} key={field.id}> - {intersperse(field.relatives.map(relative => - ( ( + )), ' ')} + /> + )), ' ')} ); } @@ -150,8 +154,8 @@ export default class NodeDetailsTableRow extends React.Component { const { pageX, pageY } = ev; const { originX, originY } = this.mouseDrag; const movedTheMouseTooMuch = ( - Math.abs(originX - pageX) > thresholdPx || - Math.abs(originY - pageY) > thresholdPx + Math.abs(originX - pageX) > thresholdPx + || Math.abs(originY - pageY) > thresholdPx ); if (movedTheMouseTooMuch && originX && originY) { return; diff --git a/client/app/scripts/components/node-details/node-details-table.js b/client/app/scripts/components/node-details/node-details-table.js index d235541d4..5a68e9ab8 100644 --- a/client/app/scripts/components/node-details/node-details-table.js +++ b/client/app/scripts/components/node-details/node-details-table.js @@ -1,7 +1,9 @@ import React from 'react'; import classNames from 'classnames'; import { connect } from 'react-redux'; -import { find, get, union, sortBy, groupBy, concat, debounce } from 'lodash'; +import { + find, get, union, sortBy, groupBy, concat, debounce +} from 'lodash'; import { NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT } from '../../constants/limits'; import { TABLE_ROW_FOCUS_DEBOUNCE_INTERVAL } from '../../constants/timer'; @@ -49,7 +51,7 @@ function getNodeValue(node, header) { if (isIP(header)) { // Format the IPs so that they are sorted numerically. return ipToPaddedString(field.value); - } else if (isNumeric(header)) { + } if (isNumeric(header)) { return parseFloat(field.value); } return field.value; @@ -218,8 +220,8 @@ class NodeDetailsTable extends React.Component { const sortedBy = this.state.sortedBy || getDefaultSortedBy(columns, this.props.nodes); const sortedByHeader = this.getColumnHeaders().find(h => h.id === sortedBy); - const sortedDesc = (this.state.sortedDesc === null) ? - defaultSortDesc(sortedByHeader) : this.state.sortedDesc; + const sortedDesc = (this.state.sortedDesc === null) + ? defaultSortDesc(sortedByHeader) : this.state.sortedDesc; let nodes = getSortedNodes(this.props.nodes, sortedByHeader, sortedDesc); @@ -261,12 +263,14 @@ class NodeDetailsTable extends React.Component {
diff --git a/client/app/scripts/components/node-details/node-details-table-row.js b/client/app/scripts/components/node-details/node-details-table-row.js index 15553d4a9..ec88502b8 100644 --- a/client/app/scripts/components/node-details/node-details-table-row.js +++ b/client/app/scripts/components/node-details/node-details-table-row.js @@ -54,14 +54,17 @@ function renderValues(node, columns = [], columnStyles = [], timestamp = null, t title={title} style={style} key={field.id}> - {field.dataType === 'link' ? - {value} - : - value} + {field.dataType === 'link' + ? ( + + {value} + + ) + : value}
- {this.props.nodes && this.props.nodes.length > 0 && 0 && ( + } + /> + )} ))} - {!layoutNodes.isEmpty() && } + /> + )} ); } diff --git a/client/app/scripts/components/nodes-resources/node-resources-metric-box-info.js b/client/app/scripts/components/nodes-resources/node-resources-metric-box-info.js index e16540167..659675927 100644 --- a/client/app/scripts/components/nodes-resources/node-resources-metric-box-info.js +++ b/client/app/scripts/components/nodes-resources/node-resources-metric-box-info.js @@ -13,11 +13,21 @@ export default class NodeResourcesMetricBoxInfo extends React.Component { {showExtendedInfo ? humanizedRelativeConsumption : humanizedAbsoluteConsumption} - used - {showExtendedInfo && + + {' '} +used + {showExtendedInfo + && ( - {' - '}({humanizedAbsoluteConsumption} / {humanizedTotalCapacity}) + {' - '} +( + {humanizedAbsoluteConsumption} + {' '} +/ + {humanizedTotalCapacity} +) + ) } ); diff --git a/client/app/scripts/components/nodes-resources/node-resources-metric-box.js b/client/app/scripts/components/nodes-resources/node-resources-metric-box.js index 161257e1b..896c38de6 100644 --- a/client/app/scripts/components/nodes-resources/node-resources-metric-box.js +++ b/client/app/scripts/components/nodes-resources/node-resources-metric-box.js @@ -112,9 +112,9 @@ class NodeResourcesMetricBox extends React.Component { // TODO: Show `+ 31 nodes` kind of tag in their stead. if (!showNode) return null; - const resourceUsageTooltipInfo = showCapacity ? - metricSummary.get('humanizedRelativeConsumption') : - metricSummary.get('humanizedAbsoluteConsumption'); + const resourceUsageTooltipInfo = showCapacity + ? metricSummary.get('humanizedRelativeConsumption') + : metricSummary.get('humanizedAbsoluteConsumption'); return ( - {label} - {type} usage at {resourceUsageTooltipInfo} - {showCapacity && + {label} + {' '} +- + {' '} + {type} + {' '} +usage at + {' '} + {resourceUsageTooltipInfo} + + {showCapacity && ( + } + /> + )} - {showInfo && } + /> + )} ); } diff --git a/client/app/scripts/components/nodes.js b/client/app/scripts/components/nodes.js index e7ec56c52..cfd61ec7c 100644 --- a/client/app/scripts/components/nodes.js +++ b/client/app/scripts/components/nodes.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import NodesChart from '../charts/nodes-chart'; import NodesGrid from '../charts/nodes-grid'; -import NodesResources from '../components/nodes-resources'; +import NodesResources from './nodes-resources'; import NodesError from '../charts/nodes-error'; import DelayedShow from '../utils/delayed-show'; import { Loading, getNodeType } from './loading'; @@ -44,9 +44,9 @@ class Nodes extends React.Component { return ( ); } diff --git a/client/app/scripts/components/plugins.js b/client/app/scripts/components/plugins.js index 753755349..3a56f9f50 100644 --- a/client/app/scripts/components/plugins.js +++ b/client/app/scripts/components/plugins.js @@ -10,7 +10,16 @@ const Plugin = ({ }) => { const error = status !== 'ok'; const className = classNames({ error }); - const tip = (Description: {description}
Status: {status}
); + const tip = ( + +Description: + {description} +
+Status: + {' '} + {status} +
+ ); // Inner span to hold styling so we don't effect the "before:content" return ( diff --git a/client/app/scripts/components/search.js b/client/app/scripts/components/search.js index 193da8801..7b9840c19 100644 --- a/client/app/scripts/components/search.js +++ b/client/app/scripts/components/search.js @@ -4,7 +4,9 @@ import { isEmpty } from 'lodash'; import { Search } from 'weaveworks-ui-components'; import styled from 'styled-components'; -import { blurSearch, focusSearch, updateSearch, toggleHelp } from '../actions/app-actions'; +import { + blurSearch, focusSearch, updateSearch, toggleHelp +} from '../actions/app-actions'; import { searchMatchCountByTopologySelector } from '../selectors/search'; import { isResourceViewModeSelector } from '../selectors/topology'; import { slugify } from '../utils/string-utils'; @@ -107,7 +109,9 @@ class SearchComponent extends React.Component { onBlur={this.props.blurSearch} /> - {searchHint} diff --git a/client/app/scripts/components/show-more.js b/client/app/scripts/components/show-more.js index 15868ef62..3744dabe6 100644 --- a/client/app/scripts/components/show-more.js +++ b/client/app/scripts/components/show-more.js @@ -24,7 +24,9 @@ export default class ShowMore extends React.PureComponent { } return (
- {limitActionText} + {limitActionText} + {' '} +
); } diff --git a/client/app/scripts/components/sparkline.js b/client/app/scripts/components/sparkline.js index 9ac381a61..e5b814fbd 100644 --- a/client/app/scripts/components/sparkline.js +++ b/client/app/scripts/components/sparkline.js @@ -72,8 +72,8 @@ export default class Sparkline extends React.Component { const min = formatMetricSvg(d3Min(data, d => d.value), this.props); const max = formatMetricSvg(d3Max(data, d => d.value), this.props); const mean = formatMetricSvg(d3Mean(data, d => d.value), this.props); - const title = `Last ${Math.round((lastDate - firstDate) / 1000)} seconds, ` + - `${data.length} samples, min: ${min}, max: ${max}, mean: ${mean}`; + const title = `Last ${Math.round((lastDate - firstDate) / 1000)} seconds, ` + + `${data.length} samples, min: ${min}, max: ${max}, mean: ${mean}`; return { data, lastX, lastY, title @@ -122,7 +122,8 @@ export default class Sparkline extends React.Component { strokeDasharray={strokeDasharray} d={this.line(graph.data)} /> - {hasData && } + /> + )} ); diff --git a/client/app/scripts/components/terminal-app.js b/client/app/scripts/components/terminal-app.js index 98484f6ef..d8819aa5f 100644 --- a/client/app/scripts/components/terminal-app.js +++ b/client/app/scripts/components/terminal-app.js @@ -51,12 +51,14 @@ class TerminalApp extends React.Component { return (
- {this.props.controlPipe && } + embedded={false} /> + )}
); } diff --git a/client/app/scripts/components/terminal.js b/client/app/scripts/components/terminal.js index 5e8d874d9..e1e6c5a9f 100644 --- a/client/app/scripts/components/terminal.js +++ b/client/app/scripts/components/terminal.js @@ -10,7 +10,9 @@ import * as fit from 'xterm/lib/addons/fit/fit'; import { closeTerminal } from '../actions/app-actions'; import { getNeutralColor } from '../utils/color-utils'; import { setDocumentTitle } from '../utils/title-utils'; -import { getPipeStatus, deletePipe, doResizeTty, getWebsocketUrl, basePath } from '../utils/web-api-utils'; +import { + getPipeStatus, deletePipe, doResizeTty, getWebsocketUrl, basePath +} from '../utils/web-api-utils'; const log = debug('scope:terminal'); @@ -327,6 +329,7 @@ class Terminal extends React.Component { ); } + getControlStatusIcon() { const icon = this.props.controlStatus && this.props.controlStatus.get('control').icon; return ( @@ -339,8 +342,7 @@ class Terminal extends React.Component { } function mapStateToProps(state, ownProps) { - const controlStatus = state.get('controlPipes').find(pipe => - pipe.get('nodeId') === ownProps.pipe.get('nodeId')); + const controlStatus = state.get('controlPipes').find(pipe => pipe.get('nodeId') === ownProps.pipe.get('nodeId')); return { controlStatus }; } diff --git a/client/app/scripts/components/time-control.js b/client/app/scripts/components/time-control.js index 59593447e..548aca887 100644 --- a/client/app/scripts/components/time-control.js +++ b/client/app/scripts/components/time-control.js @@ -64,10 +64,14 @@ class TimeControl extends React.Component { - {isPaused && + {isPaused + && ( - Showing state from + Showing state from + {' '} + + ) } ); diff --git a/client/app/scripts/components/topology-options.js b/client/app/scripts/components/topology-options.js index 29896023b..83c6a865b 100644 --- a/client/app/scripts/components/topology-options.js +++ b/client/app/scripts/components/topology-options.js @@ -101,7 +101,8 @@ class TopologyOptions extends React.Component { return (
- {option.get('selectType') === 'union' && + {option.get('selectType') === 'union' + && ( + ) } {option.get('options').map(item => ( Save raw data as JSON - {pausedAt && ({pausedAt})} + {pausedAt && ( + + {' '} +( + {pausedAt} +) + + )}
diff --git a/client/app/scripts/components/zoomable-canvas.js b/client/app/scripts/components/zoomable-canvas.js index f9801ae2b..51b51c73e 100644 --- a/client/app/scripts/components/zoomable-canvas.js +++ b/client/app/scripts/components/zoomable-canvas.js @@ -8,8 +8,8 @@ import { drag } from 'd3-drag'; import { event as d3Event, select } from 'd3-selection'; import { zoomFactor } from 'weaveworks-ui-components/lib/utils/zooming'; -import Logo from '../components/logo'; -import ZoomControl from '../components/zoom-control'; +import Logo from './logo'; +import ZoomControl from './zoom-control'; import { cacheZoomState } from '../actions/app-actions'; import { applyTransform, inverseTransform } from '../utils/transform-utils'; import { activeTopologyZoomCacheKeyPathSelector } from '../selectors/zooming'; @@ -116,12 +116,14 @@ class ZoomableCanvas extends React.Component { {this.props.children(this.state)} - {this.canChangeZoom() && } + /> + )}
); } diff --git a/client/app/scripts/decorators/node.js b/client/app/scripts/decorators/node.js index 2126605c0..ecafa27be 100644 --- a/client/app/scripts/decorators/node.js +++ b/client/app/scripts/decorators/node.js @@ -14,9 +14,9 @@ export function nodeResourceViewColorDecorator(node) { // Decorates the resource node with dimensions taken from its metric summary. export function nodeResourceBoxDecorator(node) { const metricSummary = node.get('metricSummary', makeMap()); - const width = metricSummary.get('showCapacity') ? - metricSummary.get('totalCapacity') : - metricSummary.get('absoluteConsumption'); + const width = metricSummary.get('showCapacity') + ? metricSummary.get('totalCapacity') + : metricSummary.get('absoluteConsumption'); const height = RESOURCES_LAYER_HEIGHT; return node.merge(makeMap({ height, width })); diff --git a/client/app/scripts/reducers/root.js b/client/app/scripts/reducers/root.js index 9ebebae6f..2cfd47d47 100644 --- a/client/app/scripts/reducers/root.js +++ b/client/app/scripts/reducers/root.js @@ -1,7 +1,9 @@ /* eslint-disable import/no-webpack-loader-syntax, import/no-unresolved */ import debug from 'debug'; import moment from 'moment'; -import { size, each, includes, isEqual } from 'lodash'; +import { + size, each, includes, isEqual +} from 'lodash'; import { fromJS, is as isDeepEqual, diff --git a/client/app/scripts/selectors/node-metric.js b/client/app/scripts/selectors/node-metric.js index 4058534fd..d788d99d4 100644 --- a/client/app/scripts/selectors/node-metric.js +++ b/client/app/scripts/selectors/node-metric.js @@ -3,7 +3,7 @@ import { createMapSelector, createListSelector } from 'reselect-map'; import { fromJS, Map as makeMap, List as makeList } from 'immutable'; import { modulo } from '../utils/math-utils'; -import { isGraphViewModeSelector, isResourceViewModeSelector } from '../selectors/topology'; +import { isGraphViewModeSelector, isResourceViewModeSelector } from './topology'; import { RESOURCE_VIEW_METRICS } from '../constants/resources'; @@ -93,8 +93,7 @@ const selectedMetricIdSelector = createSelector( availableMetricsSelector, selectedMetricTypeSelector, ], - (availableMetrics, metricType) => - (availableMetrics.find(m => m.get('label') === metricType) || makeMap()).get('id') + (availableMetrics, metricType) => (availableMetrics.find(m => m.get('label') === metricType) || makeMap()).get('id') ); const topCardNodeSelector = createSelector( diff --git a/client/app/scripts/selectors/resource-view/layout.js b/client/app/scripts/selectors/resource-view/layout.js index 44d41783b..b4fcbc002 100644 --- a/client/app/scripts/selectors/resource-view/layout.js +++ b/client/app/scripts/selectors/resource-view/layout.js @@ -22,9 +22,9 @@ const log = debug('scope:nodes-layout'); // Used for ordering the resource nodes. const resourceNodeConsumptionComparator = (node) => { const metricSummary = node.get('metricSummary'); - return metricSummary.get('showCapacity') ? - -metricSummary.get('relativeConsumption') : - -metricSummary.get('absoluteConsumption'); + return metricSummary.get('showCapacity') + ? -metricSummary.get('relativeConsumption') + : -metricSummary.get('absoluteConsumption'); }; // A list of topologies shown in the resource view of the active topology (bottom to top). @@ -85,8 +85,7 @@ const decoratedNodesByTopologySelector = createSelector( const isBaseLayer = (index === 0); const nodeParentDecorator = nodeParentDecoratorByTopologyId(parentLayerTopologyId); - const nodeMetricSummaryDecorator = - nodeMetricSummaryDecoratorByType(pinnedMetricType, showCapacity); + const nodeMetricSummaryDecorator = nodeMetricSummaryDecoratorByType(pinnedMetricType, showCapacity); // Color the node, deduce its anchor point, dimensions and info about its pinned metric. const decoratedTopologyNodes = (topologyNodes || makeMap()) @@ -158,8 +157,8 @@ export const layoutNodesByTopologyIdSelector = createSelector( // We fix it by shrinking all the children to by a factor to perfectly fit into the parent. if (totalChildrenWidth > parentWidth) { const shrinkFactor = parentWidth / totalChildrenWidth; - log(`Inconsistent data: Children of ${parentNodeId} reported to use more ` + - `resource than the node itself - shrinking by factor ${shrinkFactor}`); + log(`Inconsistent data: Children of ${parentNodeId} reported to use more ` + + `resource than the node itself - shrinking by factor ${shrinkFactor}`); // Shrink all the children. nodesBucket.forEach((_, nodeId) => { let node = positionedNodes.get(nodeId); diff --git a/client/app/scripts/selectors/search.js b/client/app/scripts/selectors/search.js index 00b16b1bb..7e0194c66 100644 --- a/client/app/scripts/selectors/search.js +++ b/client/app/scripts/selectors/search.js @@ -2,7 +2,9 @@ import { createSelector } from 'reselect'; import { createMapSelector } from 'reselect-map'; import { Map as makeMap } from 'immutable'; -import { parseQuery, searchNode, searchTopology, getSearchableFields } from '../utils/search-utils'; +import { + parseQuery, searchNode, searchTopology, getSearchableFields +} from '../utils/search-utils'; const parsedSearchQuerySelector = createSelector( diff --git a/client/app/scripts/utils/__tests__/web-api-utils-test.js b/client/app/scripts/utils/__tests__/web-api-utils-test.js index da32769c4..1b78c1fc8 100644 --- a/client/app/scripts/utils/__tests__/web-api-utils-test.js +++ b/client/app/scripts/utils/__tests__/web-api-utils-test.js @@ -1,6 +1,8 @@ import { Map as makeMap, OrderedMap as makeOrderedMap } from 'immutable'; -import { buildUrlQuery, basePath, getApiPath, getWebsocketUrl } from '../web-api-utils'; +import { + buildUrlQuery, basePath, getApiPath, getWebsocketUrl +} from '../web-api-utils'; describe('WebApiUtils', () => { diff --git a/client/app/scripts/utils/array-utils.js b/client/app/scripts/utils/array-utils.js index 4088b82a3..c3377769a 100644 --- a/client/app/scripts/utils/array-utils.js +++ b/client/app/scripts/utils/array-utils.js @@ -7,8 +7,7 @@ export function uniformSelect(array, size) { return array; } - return range(size).map(index => - array[parseInt(index * (array.length / (size - (1 - 1e-9))), 10)]); + return range(size).map(index => array[parseInt(index * (array.length / (size - (1 - 1e-9))), 10)]); } export function insertElement(array, index, element) { diff --git a/client/app/scripts/utils/hash-utils.js b/client/app/scripts/utils/hash-utils.js index 31cbbb216..76c358d38 100644 --- a/client/app/scripts/utils/hash-utils.js +++ b/client/app/scripts/utils/hash-utils.js @@ -1,4 +1,6 @@ -import { isPlainObject, mapValues, isEmpty, omitBy } from 'lodash'; +import { + isPlainObject, mapValues, isEmpty, omitBy +} from 'lodash'; export function hashDifferenceDeep(A, B) { diff --git a/client/app/scripts/utils/metric-utils.js b/client/app/scripts/utils/metric-utils.js index 8bdad12c2..d7731f46c 100644 --- a/client/app/scripts/utils/metric-utils.js +++ b/client/app/scripts/utils/metric-utils.js @@ -57,12 +57,12 @@ export function getMetricColor(metric) { : metric && metric.get('id'); if (/mem/.test(metricId)) { return 'steelBlue'; - } else if (/cpu/.test(metricId)) { + } if (/cpu/.test(metricId)) { return colors('cpu').toString(); - } else if (/files/.test(metricId)) { + } if (/files/.test(metricId)) { // purple return '#9467bd'; - } else if (/load/.test(metricId)) { + } if (/load/.test(metricId)) { return colors('load').toString(); } return 'steelBlue'; diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index 58f376ffa..df582cd24 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -1,7 +1,9 @@ import page from 'page'; import stableStringify from 'json-stable-stringify'; import { fromJS, is as isDeepEqual } from 'immutable'; -import { each, omit, omitBy, isEmpty } from 'lodash'; +import { + each, omit, omitBy, isEmpty +} from 'lodash'; import { route } from '../actions/app-actions'; import { hashDifferenceDeep } from './hash-utils'; diff --git a/client/app/scripts/utils/topology-utils.js b/client/app/scripts/utils/topology-utils.js index 932f4f967..2c6991164 100644 --- a/client/app/scripts/utils/topology-utils.js +++ b/client/app/scripts/utils/topology-utils.js @@ -128,9 +128,9 @@ export function setTopologyUrlsById(topologyUrlsById, topologies) { export function filterHiddenTopologies(topologies, currentTopology) { currentTopology = currentTopology || makeMap(); - return topologies.filter(t => (!t.hide_if_empty || t.stats.node_count > 0 || - t.stats.filtered_nodes > 0 || t.id === currentTopology.get('id') || - t.id === currentTopology.get('parentId'))); + return topologies.filter(t => (!t.hide_if_empty || t.stats.node_count > 0 + || t.stats.filtered_nodes > 0 || t.id === currentTopology.get('id') + || t.id === currentTopology.get('parentId'))); } export function getCurrentTopologyOptions(state) { diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index dfbb2096d..2864581f1 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -11,7 +11,7 @@ import { receiveNodesForTopology, receiveNodes, } from '../actions/app-actions'; -import { getCurrentTopologyUrl } from '../utils/topology-utils'; +import { getCurrentTopologyUrl } from './topology-utils'; import { layersTopologyIdsSelector } from '../selectors/resource-view/layout'; import { activeTopologyOptionsSelector } from '../selectors/topology'; import { isPausedSelector } from '../selectors/time-travel'; @@ -410,8 +410,8 @@ export function doControlRequest(nodeId, control, dispatch) { if (res) { if (res.pipe) { dispatch(blurSearch()); - const resizeTtyControl = res.resize_tty_control && - {id: res.resize_tty_control, nodeId: control.nodeId, probeId: control.probeId}; + const resizeTtyControl = res.resize_tty_control + && {id: res.resize_tty_control, nodeId: control.nodeId, probeId: control.probeId}; dispatch(receiveControlPipe( res.pipe, nodeId, From 3472bd4cc59b6af8ab28253998fa172f48b3db67 Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Mon, 1 Jul 2019 10:07:42 +0200 Subject: [PATCH 03/14] workaround Error: Cannot find module 'eslint/lib/formatters/stylish' by using unreleased eslint-loader (waiting for release) --- client/package.json | 2 +- client/yarn.lock | 27 ++------------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/client/package.json b/client/package.json index 3414c1255..047b751c5 100644 --- a/client/package.json +++ b/client/package.json @@ -65,7 +65,7 @@ "css-loader": "2.1.1", "eslint": "6.0.1", "eslint-config-airbnb": "17.1.0", - "eslint-loader": "2.1.2", + "eslint-loader": "https://github.com/webpack-contrib/eslint-loader#b6c3938aae61c0390ac8d941af50cf36df14cfc3", "eslint-plugin-import": "2.18.0", "eslint-plugin-jsx-a11y": "6.2.3", "eslint-plugin-react": "7.14.2", diff --git a/client/yarn.lock b/client/yarn.lock index 3de308ac6..10683d733 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -716,7 +716,6 @@ "@babel/runtime@^7.4.5": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12" - integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ== dependencies: regenerator-runtime "^0.13.2" @@ -1247,7 +1246,6 @@ argparse@^1.0.7: aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" - integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= dependencies: ast-types-flow "0.0.7" commander "^2.11.0" @@ -1418,7 +1416,6 @@ aws4@^1.8.0: axobject-query@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" - integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww== dependencies: ast-types-flow "0.0.7" @@ -1433,7 +1430,6 @@ babel-code-frame@^6.26.0: babel-eslint@10.0.2: version "10.0.2" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.2.tgz#182d5ac204579ff0881684b040560fdcc1558456" - integrity sha512-UdsurWPtgiPgpJ06ryUnuaSXC2s0WoSZnQmEpbAH65XZSdwowgN5MvyP7e88nW07FYXv72erVtpBkxyDVKhH1Q== dependencies: "@babel/code-frame" "^7.0.0" "@babel/parser" "^7.0.0" @@ -2582,7 +2578,6 @@ dagre@0.8.4: damerau-levenshtein@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz#780cf7144eb2e8dbd1c3bb83ae31100ccc31a414" - integrity sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA== dashdash@^1.12.0: version "1.14.1" @@ -2657,7 +2652,6 @@ define-properties@^1.1.2: define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== dependencies: object-keys "^1.0.12" @@ -2762,7 +2756,6 @@ doctrine@1.5.0, doctrine@^1.2.2: doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" @@ -3075,7 +3068,6 @@ escope@^3.6.0: eslint-config-airbnb-base@^13.1.0: version "13.1.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" - integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw== dependencies: eslint-restricted-globals "^0.1.1" object.assign "^4.1.0" @@ -3084,7 +3076,6 @@ eslint-config-airbnb-base@^13.1.0: eslint-config-airbnb@17.1.0: version "17.1.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" - integrity sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw== dependencies: eslint-config-airbnb-base "^13.1.0" object.assign "^4.1.0" @@ -3093,14 +3084,13 @@ eslint-config-airbnb@17.1.0: eslint-import-resolver-node@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" - integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q== dependencies: debug "^2.6.9" resolve "^1.5.0" -eslint-loader@2.1.2: +"eslint-loader@https://github.com/webpack-contrib/eslint-loader#b6c3938aae61c0390ac8d941af50cf36df14cfc3": version "2.1.2" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.1.2.tgz#453542a1230d6ffac90e4e7cb9cadba9d851be68" + resolved "https://github.com/webpack-contrib/eslint-loader#b6c3938aae61c0390ac8d941af50cf36df14cfc3" dependencies: loader-fs-cache "^1.0.0" loader-utils "^1.0.2" @@ -3111,7 +3101,6 @@ eslint-loader@2.1.2: eslint-module-utils@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a" - integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw== dependencies: debug "^2.6.8" pkg-dir "^2.0.0" @@ -3119,7 +3108,6 @@ eslint-module-utils@^2.4.0: eslint-plugin-import@2.18.0: version "2.18.0" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.0.tgz#7a5ba8d32622fb35eb9c8db195c2090bd18a3678" - integrity sha512-PZpAEC4gj/6DEMMoU2Df01C5c50r7zdGIN52Yfi7CvvWaYssG7Jt5R9nFG5gmqodxNOz9vQS87xk6Izdtpdrig== dependencies: array-includes "^3.0.3" contains-path "^0.1.0" @@ -3136,7 +3124,6 @@ eslint-plugin-import@2.18.0: eslint-plugin-jsx-a11y@6.2.3: version "6.2.3" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" - integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== dependencies: "@babel/runtime" "^7.4.5" aria-query "^3.0.0" @@ -3151,7 +3138,6 @@ eslint-plugin-jsx-a11y@6.2.3: eslint-plugin-react@7.14.2: version "7.14.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.2.tgz#94c193cc77a899ac0ecbb2766fbef88685b7ecc1" - integrity sha512-jZdnKe3ip7FQOdjxks9XPN0pjUKZYq48OggNMd16Sk+8VXx6JOvXmlElxROCgp7tiUsTsze3jd78s/9AFJP2mA== dependencies: array-includes "^3.0.3" doctrine "^2.1.0" @@ -3170,7 +3156,6 @@ eslint-restricted-globals@^0.1.1: eslint-scope@3.7.1, eslint-scope@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3193,7 +3178,6 @@ eslint-visitor-keys@^1.0.0: eslint@6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.0.1.tgz#4a32181d72cb999d6f54151df7d337131f81cda7" - integrity sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3280,7 +3264,6 @@ espree@^3.1.6: espree@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6" - integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q== dependencies: acorn "^6.0.7" acorn-jsx "^5.0.0" @@ -5408,14 +5391,12 @@ jsprim@^1.2.2: jsx-ast-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz#0ee4e2c971fb9601c67b5641b71be80faecf0b36" - integrity sha512-yDGDG2DS4JcqhA6blsuYbtsT09xL8AoLuUR2Gb5exrw7UEM19sBcOTq+YBBhrNbl0PUC4R4LnFu+dHg2HKeVvA== dependencies: array-includes "^3.0.3" jsx-ast-utils@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz#4d4973ebf8b9d2837ee91a8208cc66f3a2776cfb" - integrity sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ== dependencies: array-includes "^3.0.3" object.assign "^4.1.0" @@ -6341,7 +6322,6 @@ object.assign@^4.1.0: object.entries@^1.0.4, object.entries@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" - integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== dependencies: define-properties "^1.1.3" es-abstract "^1.12.0" @@ -6351,7 +6331,6 @@ object.entries@^1.0.4, object.entries@^1.1.0: object.fromentries@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.0.tgz#49a543d92151f8277b3ac9600f1e930b189d30ab" - integrity sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA== dependencies: define-properties "^1.1.2" es-abstract "^1.11.0" @@ -6381,7 +6360,6 @@ object.pick@^1.3.0: object.values@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.0.tgz#bf6810ef5da3e5325790eaaa2be213ea84624da9" - integrity sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg== dependencies: define-properties "^1.1.3" es-abstract "^1.12.0" @@ -7510,7 +7488,6 @@ regenerator-runtime@^0.12.0: regenerator-runtime@^0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" - integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== regenerator-transform@^0.13.4: version "0.13.4" From e5f9c2df51221226c2647addba23c55e1f1a64aa Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Mon, 1 Jul 2019 17:44:17 +0200 Subject: [PATCH 04/14] Ignore react/destructuring-assignment for now as per discussion in https://github.com/weaveworks/scope/pull/3643#issuecomment-507233272 --- client/.eslintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/client/.eslintrc b/client/.eslintrc index 519fa3361..81022730e 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -31,6 +31,7 @@ "no-param-reassign": 0, "no-restricted-properties": 0, "object-curly-spacing": 0, + "react/destructuring-assignment": 0, "react/jsx-closing-bracket-location": 0, "react/jsx-filename-extension": [ 2, From f2c371a87b1801886e26b228962ba2b538eb08a8 Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Mon, 1 Jul 2019 17:50:04 +0200 Subject: [PATCH 05/14] wants 4 spaces --- client/app/scripts/components/help-panel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/app/scripts/components/help-panel.js b/client/app/scripts/components/help-panel.js index 63cb44910..9e7d6b6a0 100644 --- a/client/app/scripts/components/help-panel.js +++ b/client/app/scripts/components/help-panel.js @@ -86,7 +86,7 @@ const METRIC_SEARCHES = [ CPU {' '} greater than 4% - , + , term: 'cpu > 4%' }, { @@ -94,7 +94,7 @@ greater than 4% Memory {' '} less than 10 megabytes - , + , term: 'memory < 10mb' }, ]; From 0a53475d37c6f8621b2b5da20ed9ed13e6560f2d Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Tue, 16 Jul 2019 18:00:29 +0200 Subject: [PATCH 06/14] update some node modules again --- client/package.json | 4 ++-- client/yarn.lock | 47 +++++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/client/package.json b/client/package.json index 047b751c5..fcb69fc97 100644 --- a/client/package.json +++ b/client/package.json @@ -8,7 +8,7 @@ "main": "index.js", "dependencies": { "@babel/polyfill": "^7.0.0", - "babel-plugin-lodash": "3.3.2", + "babel-plugin-lodash": "3.3.4", "classnames": "2.2.5", "d3-array": "1.2.1", "d3-color": "1.0.3", @@ -65,7 +65,7 @@ "css-loader": "2.1.1", "eslint": "6.0.1", "eslint-config-airbnb": "17.1.0", - "eslint-loader": "https://github.com/webpack-contrib/eslint-loader#b6c3938aae61c0390ac8d941af50cf36df14cfc3", + "eslint-loader": "2.2.1", "eslint-plugin-import": "2.18.0", "eslint-plugin-jsx-a11y": "6.2.3", "eslint-plugin-react": "7.14.2", diff --git a/client/yarn.lock b/client/yarn.lock index 10683d733..59a28bd66 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -212,9 +212,10 @@ dependencies: "@babel/types" "^7.0.0" -"@babel/helper-module-imports@^7.0.0": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== dependencies: "@babel/types" "^7.0.0" @@ -803,6 +804,15 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.0.0-beta.49": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" + integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@babel/types@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" @@ -1455,13 +1465,6 @@ babel-helper-get-function-arity@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-helper-module-imports@^7.0.0-beta.3: - version "7.0.0-beta.3" - resolved "https://registry.yarnpkg.com/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz#e15764e3af9c8e11810c09f78f498a2bdc71585a" - dependencies: - babel-types "7.0.0-beta.3" - lodash "^4.2.0" - babel-jest@24.8.0, babel-jest@^24.8.0: version "24.8.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.8.0.tgz#5c15ff2b28e20b0f45df43fe6b7f2aae93dba589" @@ -1503,14 +1506,15 @@ babel-plugin-jest-hoist@^24.6.0: dependencies: "@types/babel__traverse" "^7.0.6" -babel-plugin-lodash@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.2.tgz#da3a5b49ba27447f54463f6c4fa81396ccdd463f" +babel-plugin-lodash@3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz#4f6844358a1340baed182adbeffa8df9967bc196" + integrity sha512-yDZLjK7TCkWl1gpBeBGmuaDIFhZKmkoL+Cu2MUUjv5VxUZx/z7tBGBCBcQs5RI1Bkz5LLmNdjx7paOyQtMovyg== dependencies: - babel-helper-module-imports "^7.0.0-beta.3" - babel-types "^6.26.0" + "@babel/helper-module-imports" "^7.0.0-beta.49" + "@babel/types" "^7.0.0-beta.49" glob "^7.1.1" - lodash "^4.17.4" + lodash "^4.17.10" require-package-name "^2.0.1" babel-plugin-syntax-class-properties@^6.8.0: @@ -1575,14 +1579,6 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@7.0.0-beta.3: - version "7.0.0-beta.3" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.3.tgz#cd927ca70e0ae8ab05f4aab83778cfb3e6eb20b4" - dependencies: - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^2.0.0" - babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" @@ -3088,9 +3084,10 @@ eslint-import-resolver-node@^0.3.2: debug "^2.6.9" resolve "^1.5.0" -"eslint-loader@https://github.com/webpack-contrib/eslint-loader#b6c3938aae61c0390ac8d941af50cf36df14cfc3": - version "2.1.2" - resolved "https://github.com/webpack-contrib/eslint-loader#b6c3938aae61c0390ac8d941af50cf36df14cfc3" +eslint-loader@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337" + integrity sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg== dependencies: loader-fs-cache "^1.0.0" loader-utils "^1.0.2" From 630611af90e6600653cbb71060cbf160d4745fb3 Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Thu, 18 Jul 2019 12:21:39 +0200 Subject: [PATCH 07/14] update eslint-config-airbnb --- client/package.json | 2 +- client/yarn.lock | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/client/package.json b/client/package.json index fcb69fc97..33b19c3a8 100644 --- a/client/package.json +++ b/client/package.json @@ -64,7 +64,7 @@ "clean-webpack-plugin": "0.1.17", "css-loader": "2.1.1", "eslint": "6.0.1", - "eslint-config-airbnb": "17.1.0", + "eslint-config-airbnb": "17.1.1", "eslint-loader": "2.2.1", "eslint-plugin-import": "2.18.0", "eslint-plugin-jsx-a11y": "6.2.3", diff --git a/client/yarn.lock b/client/yarn.lock index 59a28bd66..5b19d32f3 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2240,6 +2240,11 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" +confusing-browser-globals@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.7.tgz#5ae852bd541a910e7ffb2dbb864a2d21a36ad29b" + integrity sha512-cgHI1azax5ATrZ8rJ+ODDML9Fvu67PimB6aNxBrc/QwSaDaM9eTfIEUHx3bBLJJ82ioSb+/5zfsMCCEJax3ByQ== + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -3061,21 +3066,23 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-config-airbnb-base@^13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c" +eslint-config-airbnb-base@^13.2.0: + version "13.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz#f6ea81459ff4dec2dda200c35f1d8f7419d57943" + integrity sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w== dependencies: - eslint-restricted-globals "^0.1.1" + confusing-browser-globals "^1.0.5" object.assign "^4.1.0" - object.entries "^1.0.4" + object.entries "^1.1.0" -eslint-config-airbnb@17.1.0: - version "17.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732" +eslint-config-airbnb@17.1.1: + version "17.1.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.1.tgz#2272e0b86bb1e2b138cdf88d07a3b6f4cda3d626" + integrity sha512-xCu//8a/aWqagKljt+1/qAM62BYZeNq04HmdevG5yUGWpja0I/xhqd6GdLRch5oetEGFiJAnvtGuTEAese53Qg== dependencies: - eslint-config-airbnb-base "^13.1.0" + eslint-config-airbnb-base "^13.2.0" object.assign "^4.1.0" - object.entries "^1.0.4" + object.entries "^1.1.0" eslint-import-resolver-node@^0.3.2: version "0.3.2" @@ -3146,10 +3153,6 @@ eslint-plugin-react@7.14.2: prop-types "^15.7.2" resolve "^1.10.1" -eslint-restricted-globals@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" - eslint-scope@3.7.1, eslint-scope@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" @@ -6316,7 +6319,7 @@ object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" -object.entries@^1.0.4, object.entries@^1.1.0: +object.entries@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" dependencies: From 97a2e00fe3f2a150fbd57346239b0294706e36f7 Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Wed, 31 Jul 2019 20:49:12 +0200 Subject: [PATCH 08/14] Bumped node to v8.10.0 --- client/.nvmrc | 2 +- client/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/.nvmrc b/client/.nvmrc index a244f6f35..6fe100505 100644 --- a/client/.nvmrc +++ b/client/.nvmrc @@ -1 +1 @@ -v8.9.0 +v8.10.0 diff --git a/client/package.json b/client/package.json index 33b19c3a8..8d5820072 100644 --- a/client/package.json +++ b/client/package.json @@ -130,6 +130,6 @@ ] }, "engines": { - "node": "^8.9.0" + "node": "^8.10.0" } } From f27d1337c8c2b942b86b2f9e2be14c5220cbc1ce Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Wed, 31 Jul 2019 21:38:09 +0200 Subject: [PATCH 09/14] Resolved a buncher of simple(r) eslint errors --- client/app/scripts/charts/nodes-grid.js | 43 ++++++---- .../app/scripts/components/cloud-feature.js | 3 + .../app/scripts/components/debug-toolbar.js | 84 +++++++++++-------- client/app/scripts/components/footer.js | 34 +++++--- client/app/scripts/components/help-panel.js | 80 ++++++++++-------- .../__tests__/node-details-table-test.js | 8 +- .../node-details-generic-table.js | 6 +- .../node-details-table-headers.js | 5 +- .../components/troubleshooting-menu.js | 14 ++-- client/app/scripts/components/zoom-control.js | 4 +- .../scripts/selectors/resource-view/layout.js | 5 +- client/app/scripts/utils/array-utils.js | 3 +- 12 files changed, 172 insertions(+), 117 deletions(-) diff --git a/client/app/scripts/charts/nodes-grid.js b/client/app/scripts/charts/nodes-grid.js index 1ee6a64bf..9d78a9158 100644 --- a/client/app/scripts/charts/nodes-grid.js +++ b/client/app/scripts/charts/nodes-grid.js @@ -1,4 +1,4 @@ -/* eslint react/jsx-no-bind: "off", no-multi-comp: "off" */ +/* eslint react/jsx-no-bind: "off" */ import React from 'react'; import styled from 'styled-components'; import { connect } from 'react-redux'; @@ -55,7 +55,11 @@ function getColumns(nodes, topologies) { .toList() .flatMap((n) => { const metadata = (n.get('metadata') || makeList()) - .map(m => makeMap({ dataType: m.get('dataType'), id: m.get('id'), label: m.get('label') })); + .map(m => makeMap({ + dataType: m.get('dataType'), + id: m.get('id'), + label: m.get('label') + })); return metadata; }) .toSet() @@ -68,7 +72,10 @@ function getColumns(nodes, topologies) { .toList() .flatMap((n) => { const metadata = (n.get('parents') || makeList()) - .map(m => makeMap({ id: m.get('topologyId'), label: topologyLabel(topologies, m.get('topologyId')) })); + .map(m => makeMap({ + id: m.get('topologyId'), + label: topologyLabel(topologies, m.get('topologyId')) + })); return metadata; }) .toSet() @@ -128,7 +135,9 @@ class NodesGrid extends React.Component { const { nodes, gridSortedBy, gridSortedDesc, searchNodeMatches, searchQuery, windowHeight, topologies } = this.props; - const height = this.tableRef ? windowHeight - this.tableRef.getBoundingClientRect().top - 30 : 0; + const height = this.tableRef + ? windowHeight - this.tableRef.getBoundingClientRect().top - 30 + : 0; const cmpStyle = { height, paddingLeft: 40, @@ -154,19 +163,19 @@ class NodesGrid extends React.Component { return (
{nodes.size > 0 && ( - )}
diff --git a/client/app/scripts/components/cloud-feature.js b/client/app/scripts/components/cloud-feature.js index 0708a37ef..440f74511 100644 --- a/client/app/scripts/components/cloud-feature.js +++ b/client/app/scripts/components/cloud-feature.js @@ -26,6 +26,8 @@ class CloudFeature extends React.Component { } } +/* eslint-disable react/forbid-prop-types */ +// TODO: Remove this component as part of https://github.com/weaveworks/scope/issues/3278. CloudFeature.contextTypes = { router: PropTypes.object, serviceStore: PropTypes.object, @@ -36,5 +38,6 @@ CloudFeature.childContextTypes = { router: PropTypes.object, store: PropTypes.object }; +/* eslint-enable react/forbid-prop-types */ export default connect()(CloudFeature); diff --git a/client/app/scripts/components/debug-toolbar.js b/client/app/scripts/components/debug-toolbar.js index 6145a57e3..9d892fa83 100644 --- a/client/app/scripts/components/debug-toolbar.js +++ b/client/app/scripts/components/debug-toolbar.js @@ -19,7 +19,7 @@ const STACK_VARIANTS = [false, true]; const METRIC_FILLS = [0, 0.1, 50, 99.9, 100]; const NETWORKS = [ 'be', 'fe', 'zb', 'db', 're', 'gh', 'jk', 'lol', 'nw' -].map(n => ({colorKey: n, id: n, label: n})); +].map(n => ({ colorKey: n, id: n, label: n })); const INTERNET = 'the-internet'; const LOREM = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor @@ -60,7 +60,7 @@ const deltaAdd = (name, adjacency = [], shape = 'circle', stack = false, network function addMetrics(availableMetrics, node, v) { const metrics = availableMetrics.size > 0 ? availableMetrics : fromJS([ - {id: 'host_cpu_usage_percent', label: 'CPU'} + { id: 'host_cpu_usage_percent', label: 'CPU' } ]); return Object.assign({}, node, { @@ -153,7 +153,7 @@ class DebugToolbar extends React.Component { } onChange(ev) { - this.setState({nodesToAdd: parseInt(ev.target.value, 10)}); + this.setState({ nodesToAdd: parseInt(ev.target.value, 10) }); } toggleColors() { @@ -285,48 +285,54 @@ class DebugToolbar extends React.Component {
Add nodes - - + + - - - + + - - - - + + + +
Logging - - - - - + + + + +
Colors - +
{this.state.showColors - && ( -
- - {LABEL_PREFIXES.map(r => ( - - - ))} - -
-
- )} + && ( + + + {LABEL_PREFIXES.map(r => ( + + + ))} + +
+
+ )} {this.state.showColors && [getNodeColor, getNodeColorDark].map(fn => ( @@ -334,7 +340,7 @@ class DebugToolbar extends React.Component { {LABEL_PREFIXES.map(r => ( {LABEL_PREFIXES.map(c => ( - ))} @@ -344,14 +350,20 @@ class DebugToolbar extends React.Component {
State - - + +
Short-lived nodes - - + +
); diff --git a/client/app/scripts/components/footer.js b/client/app/scripts/components/footer.js index 61d957554..b08f5bed2 100644 --- a/client/app/scripts/components/footer.js +++ b/client/app/scripts/components/footer.js @@ -44,16 +44,16 @@ class Footer extends React.Component {
{versionUpdate && ( - - Update available: - {' '} - {versionUpdate.get('version')} - + + Update available: + {' '} + {versionUpdate.get('version')} + ) } Version @@ -68,15 +68,21 @@ class Footer extends React.Component {
- -
diff --git a/client/app/scripts/components/help-panel.js b/client/app/scripts/components/help-panel.js index 9e7d6b6a0..a41aecc3c 100644 --- a/client/app/scripts/components/help-panel.js +++ b/client/app/scripts/components/help-panel.js @@ -7,26 +7,26 @@ import { hideHelp } from '../actions/app-actions'; const GENERAL_SHORTCUTS = [ - {key: 'esc', label: 'Close active panel'}, - {key: '/', label: 'Activate search field'}, - {key: '?', label: 'Toggle shortcut menu'}, - {key: 'g', label: 'Switch to Graph view'}, - {key: 't', label: 'Switch to Table view'}, - {key: 'r', label: 'Switch to Resources view'}, + { key: 'esc', label: 'Close active panel' }, + { key: '/', label: 'Activate search field' }, + { key: '?', label: 'Toggle shortcut menu' }, + { key: 'g', label: 'Switch to Graph view' }, + { key: 't', label: 'Switch to Table view' }, + { key: 'r', label: 'Switch to Resources view' }, ]; const CANVAS_METRIC_SHORTCUTS = [ - {key: '<', label: 'Select and pin previous metric'}, - {key: '>', label: 'Select and pin next metric'}, - {key: 'q', label: 'Unpin current metric'}, + { key: '<', label: 'Select and pin previous metric' }, + { key: '>', label: 'Select and pin next metric' }, + { key: 'q', label: 'Unpin current metric' }, ]; function renderShortcuts(cuts) { return (
- {cuts.map(({key, label}) => ( + {cuts.map(({ key, label }) => (
{key}
{label}
@@ -51,14 +51,16 @@ function renderShortcutPanel() { const BASIC_SEARCHES = [ - {label: 'All fields for foo', term: 'foo'}, + { label: 'All fields for foo', term: 'foo' }, { - label: -Any field matching - pid - {' '} -for the value 12345 - , + label: ( + + Any field matching + pid + {' '} + for the value 12345 + + ), term: 'pid: 12345' }, ]; @@ -70,11 +72,13 @@ const REGEX_SEARCHES = [ term: 'foo|bar' }, { - label: - command - {' '} -field for foobar or foobaz - , + label: ( + + command + {' '} + field for foobar or foobaz + + ), term: 'command: foo(bar|baz)' }, ]; @@ -82,19 +86,23 @@ field for foobar or foobaz const METRIC_SEARCHES = [ { - label: - CPU - {' '} -greater than 4% - , + label: ( + + CPU + {' '} + greater than 4% + + ), term: 'cpu > 4%' }, { - label: - Memory - {' '} -less than 10 megabytes - , + label: ( + + Memory + {' '} + less than 10 megabytes + + ), term: 'memory < 10mb' }, ]; @@ -103,7 +111,7 @@ less than 10 megabytes function renderSearches(searches) { return (
- {searches.map(({term, label}) => ( + {searches.map(({ term, label }) => (
@@ -137,7 +145,7 @@ function renderSearchPanel() { function renderFieldsPanel(currentTopologyName, searchableFields) { const none = ( - None + None ); const currentTopology = ( @@ -156,7 +164,7 @@ function renderFieldsPanel(currentTopologyName, searchableFields) { {' '} {currentTopology} {' '} -topology: + topology:

@@ -188,7 +196,7 @@ function HelpPanel({ }) { return (
-
+

Help

diff --git a/client/app/scripts/components/node-details/__tests__/node-details-table-test.js b/client/app/scripts/components/node-details/__tests__/node-details-table-test.js index ace198233..70323b1c4 100644 --- a/client/app/scripts/components/node-details/__tests__/node-details-table-test.js +++ b/client/app/scripts/components/node-details/__tests__/node-details-table-test.js @@ -70,7 +70,9 @@ describe('NodeDetailsTable', () => { // (that is, first by row and then by column), the indexes we are interested in are of the // form columnIndex + n * columns.length, where n >= 0. Therefore we take only the values // at the index which divided by columns.length gives a reminder columnIndex. - const filteredValues = values.filter((element, index) => index % columns.length === columnIndex); + const filteredValues = values.filter( + (element, index) => index % columns.length === columnIndex + ); // Array comparison expect(filteredValues).toEqual(expectedValues); } @@ -90,7 +92,7 @@ describe('NodeDetailsTable', () => { sortedBy="kubernetes_ip" nodeIdKey="id" nodes={nodes} - /> + /> )); @@ -126,7 +128,7 @@ describe('NodeDetailsTable', () => { sortedBy="kubernetes_namespace" nodeIdKey="id" nodes={nodes} - /> + /> )); diff --git a/client/app/scripts/components/node-details/node-details-generic-table.js b/client/app/scripts/components/node-details/node-details-generic-table.js index 6a92f29f7..ee9c15013 100644 --- a/client/app/scripts/components/node-details/node-details-generic-table.js +++ b/client/app/scripts/components/node-details/node-details-generic-table.js @@ -62,7 +62,11 @@ export default class NodeDetailsGenericTable extends React.Component { // If there are rows that would be hidden behind 'show more', keep them // expanded if any of them match the search query; otherwise hide them. if (this.state.limit > 0 && rows.length > this.state.limit) { - const hasHiddenMatch = rows.slice(this.state.limit).some(row => columns.some(column => matches.has(genericTableEntryKey(row, column)))); + const hasHiddenMatch = rows + .slice(this.state.limit) + .some( + row => columns.some(column => matches.has(genericTableEntryKey(row, column))) + ); if (!hasHiddenMatch) { notShown = rows.length - NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT; rows = rows.slice(0, this.state.limit); diff --git a/client/app/scripts/components/node-details/node-details-table-headers.js b/client/app/scripts/components/node-details/node-details-table-headers.js index 1fd45527c..48a049de5 100644 --- a/client/app/scripts/components/node-details/node-details-table-headers.js +++ b/client/app/scripts/components/node-details/node-details-table-headers.js @@ -33,8 +33,9 @@ export default class NodeDetailsTableHeaders extends React.Component { } const style = colStyles[index]; - const label = (style.width === NODE_DETAILS_TABLE_CW.XS && NODE_DETAILS_TABLE_XS_LABEL[header.id]) - ? NODE_DETAILS_TABLE_XS_LABEL[header.id] : header.label; + const label = ( + style.width === NODE_DETAILS_TABLE_CW.XS && NODE_DETAILS_TABLE_XS_LABEL[header.id] + ) ? NODE_DETAILS_TABLE_XS_LABEL[header.id] : header.label; return (
; + return ; } @@ -160,8 +160,9 @@ class NodeDetailsTable extends React.Component { } handleLimitClick() { - const limit = this.state.limit ? 0 : this.props.limit; - this.setState({ limit }); + this.setState(prevState => ({ + limit: prevState.limit ? 0 : this.props.limit + })); } focusRow(rowIndex, node) { @@ -204,7 +205,7 @@ class NodeDetailsTable extends React.Component { getColumnHeaders() { const columns = this.props.columns || []; - return [{id: 'label', label: this.props.label}].concat(columns); + return [{ id: 'label', label: this.props.label }].concat(columns); } componentDidMount() { @@ -264,12 +265,12 @@ class NodeDetailsTable extends React.Component {
+ ))}
diff --git a/client/app/scripts/components/troubleshooting-menu.js b/client/app/scripts/components/troubleshooting-menu.js index 64a2db3c7..3ce8bce22 100644 --- a/client/app/scripts/components/troubleshooting-menu.js +++ b/client/app/scripts/components/troubleshooting-menu.js @@ -37,17 +37,18 @@ class DebugMenu extends React.Component { Save raw data as JSON {pausedAt && ( - - {' '} -( - {pausedAt} -) - + + {' '} + ( + {pausedAt} + ) + )}
-
diff --git a/client/app/scripts/selectors/resource-view/layout.js b/client/app/scripts/selectors/resource-view/layout.js index b4fcbc002..c2f6b42cd 100644 --- a/client/app/scripts/selectors/resource-view/layout.js +++ b/client/app/scripts/selectors/resource-view/layout.js @@ -85,7 +85,10 @@ const decoratedNodesByTopologySelector = createSelector( const isBaseLayer = (index === 0); const nodeParentDecorator = nodeParentDecoratorByTopologyId(parentLayerTopologyId); - const nodeMetricSummaryDecorator = nodeMetricSummaryDecoratorByType(pinnedMetricType, showCapacity); + const nodeMetricSummaryDecorator = nodeMetricSummaryDecoratorByType( + pinnedMetricType, + showCapacity + ); // Color the node, deduce its anchor point, dimensions and info about its pinned metric. const decoratedTopologyNodes = (topologyNodes || makeMap()) diff --git a/client/app/scripts/utils/array-utils.js b/client/app/scripts/utils/array-utils.js index c3377769a..dfcfeef7b 100644 --- a/client/app/scripts/utils/array-utils.js +++ b/client/app/scripts/utils/array-utils.js @@ -7,7 +7,8 @@ export function uniformSelect(array, size) { return array; } - return range(size).map(index => array[parseInt(index * (array.length / (size - (1 - 1e-9))), 10)]); + return range(size) + .map(index => array[parseInt(index * (array.length / (size - (1 - 1e-9))), 10)]); } export function insertElement(array, index, element) { From 7c417bd5d6429be8ffcfb3d749369c8c9a0dedac Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Wed, 31 Jul 2019 21:45:23 +0200 Subject: [PATCH 10/14] Addressed react/no-access-state-in-setstate --- .../app/scripts/components/debug-toolbar.js | 6 ++--- .../node-details-generic-table.js | 6 ++--- .../node-details/node-details-health.js | 9 ++++--- .../node-details/node-details-info.js | 5 ++-- .../node-details-property-list.js | 5 ++-- .../node-details/node-details-relatives.js | 15 +++++------ .../node-details/node-details-table.js | 25 ++++++++++--------- client/app/scripts/components/warning.js | 5 ++-- 8 files changed, 41 insertions(+), 35 deletions(-) diff --git a/client/app/scripts/components/debug-toolbar.js b/client/app/scripts/components/debug-toolbar.js index 9d892fa83..bb84c609d 100644 --- a/client/app/scripts/components/debug-toolbar.js +++ b/client/app/scripts/components/debug-toolbar.js @@ -157,9 +157,9 @@ class DebugToolbar extends React.Component { } toggleColors() { - this.setState({ - showColors: !this.state.showColors - }); + this.setState(prevState => ({ + showColors: !prevState.showColors + })); } asyncDispatch(v) { diff --git a/client/app/scripts/components/node-details/node-details-generic-table.js b/client/app/scripts/components/node-details/node-details-generic-table.js index ee9c15013..0f9bfe544 100644 --- a/client/app/scripts/components/node-details/node-details-generic-table.js +++ b/client/app/scripts/components/node-details/node-details-generic-table.js @@ -46,9 +46,9 @@ export default class NodeDetailsGenericTable extends React.Component { } handleLimitClick() { - this.setState({ - limit: this.state.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT - }); + this.setState(prevState => ({ + limit: prevState.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT + })); } render() { diff --git a/client/app/scripts/components/node-details/node-details-health.js b/client/app/scripts/components/node-details/node-details-health.js index 82b89f063..4c724b878 100644 --- a/client/app/scripts/components/node-details/node-details-health.js +++ b/client/app/scripts/components/node-details/node-details-health.js @@ -13,8 +13,9 @@ export default class NodeDetailsHealth extends React.Component { } handleClickMore() { - const expanded = !this.state.expanded; - this.setState({expanded}); + this.setState(prevState => ({ + expanded: !prevState.expanded + })); } render() { @@ -43,7 +44,7 @@ export default class NodeDetailsHealth extends React.Component { {...item} key={item.id} topologyId={topologyId} - /> + /> ))}
@@ -52,7 +53,7 @@ export default class NodeDetailsHealth extends React.Component { {...item} key={item.id} topologyId={topologyId} - /> + /> ))}
({ + expanded: !prevState.expanded + })); } render() { diff --git a/client/app/scripts/components/node-details/node-details-property-list.js b/client/app/scripts/components/node-details/node-details-property-list.js index e72f7bf05..95585fe16 100644 --- a/client/app/scripts/components/node-details/node-details-property-list.js +++ b/client/app/scripts/components/node-details/node-details-property-list.js @@ -28,8 +28,9 @@ export default class NodeDetailsPropertyList extends React.Component { } handleLimitClick() { - const limit = this.state.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT; - this.setState({limit}); + this.setState(prevState => ({ + limit: prevState.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT + })); } render() { diff --git a/client/app/scripts/components/node-details/node-details-relatives.js b/client/app/scripts/components/node-details/node-details-relatives.js index 3e2b83794..e4af56a0d 100644 --- a/client/app/scripts/components/node-details/node-details-relatives.js +++ b/client/app/scripts/components/node-details/node-details-relatives.js @@ -15,8 +15,9 @@ export default class NodeDetailsRelatives extends React.Component { handleLimitClick(ev) { ev.preventDefault(); - const limit = this.state.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT; - this.setState({limit}); + this.setState(prevState => ({ + limit: prevState.limit ? 0 : NODE_DETAILS_DATA_ROWS_DEFAULT_LIMIT + })); } render() { @@ -41,11 +42,11 @@ export default class NodeDetailsRelatives extends React.Component { ))} {showLimitAction && ( - - {limitActionText} - + + {limitActionText} + ) } diff --git a/client/app/scripts/components/node-details/node-details-table.js b/client/app/scripts/components/node-details/node-details-table.js index 5a68e9ab8..4af2e1b8d 100644 --- a/client/app/scripts/components/node-details/node-details-table.js +++ b/client/app/scripts/components/node-details/node-details-table.js @@ -20,7 +20,7 @@ import { function getDefaultSortedBy(columns, nodes) { // default sorter specified by columns - const defaultSortColumn = find(columns, {defaultSort: true}); + const defaultSortColumn = find(columns, { defaultSort: true }); if (defaultSortColumn) { return defaultSortColumn.id; } @@ -127,7 +127,7 @@ function getSortedNodes(nodes, sortedByHeader, sortedDesc) { // have a minimal height. That prevents auto-scroll under a focus if the // number of table rows shrinks. function minHeightConstraint(height = 0) { - return
{this.props.nodes && this.props.nodes.length > 0 && ( - + )} {}, + onSortChange: () => { }, sortedBy: null, sortedDesc: null, }; diff --git a/client/app/scripts/components/warning.js b/client/app/scripts/components/warning.js index 4fadad6db..655dce638 100644 --- a/client/app/scripts/components/warning.js +++ b/client/app/scripts/components/warning.js @@ -12,8 +12,9 @@ class Warning extends React.Component { } handleClick() { - const expanded = !this.state.expanded; - this.setState({ expanded }); + this.setState(prevState => ({ + expanded: !prevState.expanded + })); } render() { From 2ab7ada568cdf2d49b67725337d9f5f93b05e331 Mon Sep 17 00:00:00 2001 From: Daniel Holbach Date: Thu, 1 Aug 2019 08:38:02 +0200 Subject: [PATCH 11/14] some more eslint updates --- client/package.json | 6 +-- client/yarn.lock | 96 +++++++++++++++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/client/package.json b/client/package.json index 8d5820072..c9a3b8eac 100644 --- a/client/package.json +++ b/client/package.json @@ -63,12 +63,12 @@ "babel-plugin-transform-object-rest-spread": "6.26.0", "clean-webpack-plugin": "0.1.17", "css-loader": "2.1.1", - "eslint": "6.0.1", + "eslint": "6.1.0", "eslint-config-airbnb": "17.1.1", "eslint-loader": "2.2.1", - "eslint-plugin-import": "2.18.0", + "eslint-plugin-import": "2.18.2", "eslint-plugin-jsx-a11y": "6.2.3", - "eslint-plugin-react": "7.14.2", + "eslint-plugin-react": "7.14.3", "express": "4.16.4", "file-loader": "1.1.11", "html-webpack-plugin": "3.2.0", diff --git a/client/yarn.lock b/client/yarn.lock index 5b19d32f3..5b7d62de2 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -3109,9 +3109,10 @@ eslint-module-utils@^2.4.0: debug "^2.6.8" pkg-dir "^2.0.0" -eslint-plugin-import@2.18.0: - version "2.18.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.0.tgz#7a5ba8d32622fb35eb9c8db195c2090bd18a3678" +eslint-plugin-import@2.18.2: + version "2.18.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6" + integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ== dependencies: array-includes "^3.0.3" contains-path "^0.1.0" @@ -3120,8 +3121,8 @@ eslint-plugin-import@2.18.0: eslint-import-resolver-node "^0.3.2" eslint-module-utils "^2.4.0" has "^1.0.3" - lodash "^4.17.11" minimatch "^3.0.4" + object.values "^1.1.0" read-pkg-up "^2.0.0" resolve "^1.11.0" @@ -3139,9 +3140,10 @@ eslint-plugin-jsx-a11y@6.2.3: has "^1.0.3" jsx-ast-utils "^2.2.1" -eslint-plugin-react@7.14.2: - version "7.14.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.2.tgz#94c193cc77a899ac0ecbb2766fbef88685b7ecc1" +eslint-plugin-react@7.14.3: + version "7.14.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.14.3.tgz#911030dd7e98ba49e1b2208599571846a66bdf13" + integrity sha512-EzdyyBWC4Uz2hPYBiEJrKCUi2Fn+BJ9B/pJQcjw5X+x/H2Nm59S4MJIvL4O5NEE0+WbnQwEBxWY03oUk+Bc3FA== dependencies: array-includes "^3.0.3" doctrine "^2.1.0" @@ -3160,9 +3162,10 @@ eslint-scope@3.7.1, eslint-scope@^3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3175,9 +3178,10 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.0.1.tgz#4a32181d72cb999d6f54151df7d337131f81cda7" +eslint@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.1.0.tgz#06438a4a278b1d84fb107d24eaaa35471986e646" + integrity sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3185,7 +3189,7 @@ eslint@6.0.1: cross-spawn "^6.0.5" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^4.0.3" + eslint-scope "^5.0.0" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" espree "^6.0.0" @@ -3193,28 +3197,29 @@ eslint@6.0.1: esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^3.1.0" + glob-parent "^5.0.0" globals "^11.7.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^6.2.2" + inquirer "^6.4.1" is-glob "^4.0.0" js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.11" + lodash "^4.17.14" minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" progress "^2.0.0" regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" table "^5.2.3" text-table "^0.2.0" + v8-compile-cache "^2.0.3" eslint@^2.7.0: version "2.13.1" @@ -3907,6 +3912,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" @@ -4472,9 +4484,10 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^6.2.2: - version "6.3.1" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.3.1.tgz#7a413b5e7950811013a3db491c61d1f3b776e8e7" +inquirer@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" + integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA== dependencies: ansi-escapes "^3.2.0" chalk "^2.4.2" @@ -4482,7 +4495,7 @@ inquirer@^6.2.2: cli-width "^2.0.0" external-editor "^3.0.3" figures "^2.0.0" - lodash "^4.17.11" + lodash "^4.17.12" mute-stream "0.0.7" run-async "^2.2.0" rxjs "^6.4.0" @@ -4697,6 +4710,13 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-hexadecimal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69" @@ -5594,6 +5614,11 @@ lodash@^4.0.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lod version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lodash@^4.17.12, lodash@^4.17.14: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + log-symbols@^2.0.0, log-symbols@^2.1.0, log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -7989,9 +8014,10 @@ semver@^5.5.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" -semver@^5.5.1: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" +semver@^6.1.2: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@~5.3.0: version "5.3.0" @@ -8435,14 +8461,19 @@ strip-indent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== strip-json-comments@~1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + style-loader@0.21.0: version "0.21.0" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.21.0.tgz#68c52e5eb2afc9ca92b6274be277ee59aea3a852" @@ -9149,6 +9180,11 @@ v8-compile-cache@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" +v8-compile-cache@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" + integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" From 183bf0f8bd4b2cbe8fc7f9c6c55e120843a711af Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Thu, 1 Aug 2019 16:08:52 +0200 Subject: [PATCH 12/14] Moved doControlRequest function into actions --- client/app/scripts/actions/app-actions.js | 65 +++++++++++++++---- .../node-details-table-node-link.js | 2 +- .../node-details-table-node-metric-link.js | 2 +- .../node-details/node-details-table-row.js | 15 +---- client/app/scripts/utils/dom-utils.js | 13 ++++ client/app/scripts/utils/web-api-utils.js | 49 ++------------ 6 files changed, 73 insertions(+), 73 deletions(-) diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index 0587ca8b6..ccc307e51 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -5,7 +5,8 @@ import ActionTypes from '../constants/action-types'; import { saveGraph } from '../utils/file-utils'; import { clearStoredViewState, updateRoute } from '../utils/router-utils'; import { - doControlRequest, + doRequest, + getApiPath, getAllNodes, getResourceViewNodesSnapshot, getNodeDetails, @@ -34,6 +35,8 @@ import { } from '../constants/naming'; +let controlErrorTimer = 0; + const log = debug('scope:app-actions'); @@ -420,17 +423,6 @@ export function closeWebsocket() { }; } -export function doControl(nodeId, control) { - return (dispatch) => { - dispatch({ - control, - nodeId, - type: ActionTypes.DO_CONTROL - }); - doControlRequest(nodeId, control, dispatch); - }; -} - export function enterEdge(edgeId) { return { edgeId, @@ -683,6 +675,53 @@ export function receiveControlPipeStatus(pipeId, status) { }; } +function doControlRequest(nodeId, control, dispatch) { + clearTimeout(controlErrorTimer); + const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/` + + `${encodeURIComponent(control.nodeId)}/${control.id}`; + doRequest({ + error: (err) => { + dispatch(receiveControlError(nodeId, err.response)); + controlErrorTimer = setTimeout(() => { + dispatch(clearControlError(nodeId)); + }, 10000); + }, + method: 'POST', + success: (res) => { + dispatch(receiveControlSuccess(nodeId)); + if (res) { + if (res.pipe) { + dispatch(blurSearch()); + const resizeTtyControl = res.resize_tty_control + && { id: res.resize_tty_control, nodeId: control.nodeId, probeId: control.probeId }; + dispatch(receiveControlPipe( + res.pipe, + nodeId, + res.raw_tty, + resizeTtyControl, + control + )); + } + if (res.removedNode) { + dispatch(receiveControlNodeRemoved(nodeId)); + } + } + }, + url + }); +} + +export function doControl(nodeId, control) { + return (dispatch) => { + dispatch({ + control, + nodeId, + type: ActionTypes.DO_CONTROL + }); + doControlRequest(nodeId, control, dispatch); + }; +} + export function receiveError(errorUrl) { return { errorUrl, @@ -745,7 +784,7 @@ export function route(urlState) { export function resetLocalViewState() { return (dispatch) => { - dispatch({type: ActionTypes.RESET_LOCAL_VIEW_STATE}); + dispatch({ type: ActionTypes.RESET_LOCAL_VIEW_STATE }); clearStoredViewState(); // eslint-disable-next-line prefer-destructuring window.location.href = window.location.href.split('#')[0]; diff --git a/client/app/scripts/components/node-details/node-details-table-node-link.js b/client/app/scripts/components/node-details/node-details-table-node-link.js index 1c3303b9b..45820b4d2 100644 --- a/client/app/scripts/components/node-details/node-details-table-node-link.js +++ b/client/app/scripts/components/node-details/node-details-table-node-link.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import { clickRelative } from '../../actions/app-actions'; import { trackAnalyticsEvent } from '../../utils/tracking-utils'; -import { dismissRowClickProps } from './node-details-table-row'; +import { dismissRowClickProps } from '../../utils/dom-utils'; class NodeDetailsTableNodeLink extends React.Component { diff --git a/client/app/scripts/components/node-details/node-details-table-node-metric-link.js b/client/app/scripts/components/node-details/node-details-table-node-metric-link.js index 3749fce82..e097adf47 100644 --- a/client/app/scripts/components/node-details/node-details-table-node-metric-link.js +++ b/client/app/scripts/components/node-details/node-details-table-node-metric-link.js @@ -3,7 +3,7 @@ import React from 'react'; import CloudLink from '../cloud-link'; import { formatMetric } from '../../utils/string-utils'; import { trackAnalyticsEvent } from '../../utils/tracking-utils'; -import { dismissRowClickProps } from './node-details-table-row'; +import { dismissRowClickProps } from '../../utils/dom-utils'; class NodeDetailsTableNodeMetricLink extends React.Component { constructor(props) { diff --git a/client/app/scripts/components/node-details/node-details-table-row.js b/client/app/scripts/components/node-details/node-details-table-row.js index ec88502b8..8e452a4d5 100644 --- a/client/app/scripts/components/node-details/node-details-table-row.js +++ b/client/app/scripts/components/node-details/node-details-table-row.js @@ -102,19 +102,6 @@ function renderValues(node, columns = [], columnStyles = [], timestamp = null, t }); } -/** - * Table row children may react to onClick events but the row - * itself does detect a click by looking at onMouseUp. To stop - * the bubbling of clicks on child elements we need to dismiss - * the onMouseUp event. - */ -export const dismissRowClickProps = { - onMouseUp: (ev) => { - ev.preventDefault(); - ev.stopPropagation(); - } -}; - export default class NodeDetailsTableRow extends React.Component { constructor(props, context) { super(props, context); @@ -186,7 +173,7 @@ export default class NodeDetailsTableRow extends React.Component { onMouseLeave={this.onMouseLeave} className={className}> {values} diff --git a/client/app/scripts/utils/dom-utils.js b/client/app/scripts/utils/dom-utils.js index b993a5136..1ab2bcf36 100644 --- a/client/app/scripts/utils/dom-utils.js +++ b/client/app/scripts/utils/dom-utils.js @@ -14,3 +14,16 @@ export function encodeIdAttribute(id) { export function decodeIdAttribute(id) { return id.replace(/__u(\d+)__/gm, (m, d) => String.fromCharCode(d)); } + +/** + * Table row children may react to onClick events but the row + * itself does detect a click by looking at onMouseUp. To stop + * the bubbling of clicks on child elements we need to dismiss + * the onMouseUp event. + */ +export const dismissRowClickProps = { + onMouseUp: (ev) => { + ev.preventDefault(); + ev.stopPropagation(); + } +}; diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index 2864581f1..b37bac8cb 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -4,10 +4,9 @@ import { defaults } from 'lodash'; import { Map as makeMap, List } from 'immutable'; import { - blurSearch, clearControlError, closeWebsocket, openWebsocket, receiveError, - receiveApiDetails, receiveNodesDelta, receiveNodeDetails, receiveControlError, - receiveControlNodeRemoved, receiveControlPipe, receiveControlPipeStatus, - receiveControlSuccess, receiveTopologies, receiveNotFound, + closeWebsocket, openWebsocket, receiveError, + receiveApiDetails, receiveNodesDelta, receiveNodeDetails, + receiveControlPipeStatus, receiveTopologies, receiveNotFound, receiveNodesForTopology, receiveNodes, } from '../actions/app-actions'; @@ -42,7 +41,6 @@ let socket; let reconnectTimer = 0; let topologyTimer = 0; let apiDetailsTimer = 0; -let controlErrorTimer = 0; let currentUrl = null; let createWebsocketAt = null; let firstMessageOnWebsocketAt = null; @@ -182,7 +180,7 @@ function createWebsocket(websocketUrl, getState, dispatch) { * XHR wrapper. Applies a CSRF token (if it exists) and content-type to all requests. * Any opts that get passed in will override the defaults. */ -function doRequest(opts) { +export function doRequest(opts) { const config = defaults(opts, { contentType: 'application/json', type: 'json' @@ -393,49 +391,12 @@ export function getApiDetails(dispatch) { }); } -export function doControlRequest(nodeId, control, dispatch) { - clearTimeout(controlErrorTimer); - const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/` - + `${encodeURIComponent(control.nodeId)}/${control.id}`; - doRequest({ - error: (err) => { - dispatch(receiveControlError(nodeId, err.response)); - controlErrorTimer = setTimeout(() => { - dispatch(clearControlError(nodeId)); - }, 10000); - }, - method: 'POST', - success: (res) => { - dispatch(receiveControlSuccess(nodeId)); - if (res) { - if (res.pipe) { - dispatch(blurSearch()); - const resizeTtyControl = res.resize_tty_control - && {id: res.resize_tty_control, nodeId: control.nodeId, probeId: control.probeId}; - dispatch(receiveControlPipe( - res.pipe, - nodeId, - res.raw_tty, - resizeTtyControl, - control - )); - } - if (res.removedNode) { - dispatch(receiveControlNodeRemoved(nodeId)); - } - } - }, - url - }); -} - - export function doResizeTty(pipeId, control, cols, rows) { const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/` + `${encodeURIComponent(control.nodeId)}/${control.id}`; return doRequest({ - data: JSON.stringify({height: rows.toString(), pipeID: pipeId, width: cols.toString()}), + data: JSON.stringify({ height: rows.toString(), pipeID: pipeId, width: cols.toString() }), method: 'POST', url, }) From c2fa42f514d9bbfbe8acade1111b309af1921d71 Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Fri, 2 Aug 2019 15:31:19 +0200 Subject: [PATCH 13/14] Resolved router utils dependency cycle --- client/app/scripts/components/app.js | 3 +- client/app/scripts/router.js | 64 ++++++++++++++++++++++ client/app/scripts/utils/router-utils.js | 69 ++---------------------- 3 files changed, 71 insertions(+), 65 deletions(-) create mode 100644 client/app/scripts/router.js diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 32abc25d5..278bd6f56 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -42,7 +42,8 @@ import TimeTravelWrapper from './time-travel-wrapper'; import ViewModeSelector from './view-mode-selector'; import NetworkSelector from './networks-selector'; import DebugToolbar, { showingDebugToolbar, toggleDebugToolbar } from './debug-toolbar'; -import { getRouter, getUrlState } from '../utils/router-utils'; +import { getUrlState } from '../utils/router-utils'; +import { getRouter } from '../router'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { availableNetworksSelector } from '../selectors/node-networks'; import { timeTravelSupportedSelector } from '../selectors/time-travel'; diff --git a/client/app/scripts/router.js b/client/app/scripts/router.js new file mode 100644 index 000000000..f1fc9571f --- /dev/null +++ b/client/app/scripts/router.js @@ -0,0 +1,64 @@ +import page from 'page'; +import stableStringify from 'json-stable-stringify'; +import { each } from 'lodash'; + +import { route } from './actions/app-actions'; +import { storageGet, storageSet } from './utils/storage-utils'; +import { + decodeURL, encodeURL, isStoreViewStateEnabled, STORAGE_STATE_KEY +} from './utils/router-utils'; + +// Temporarily detect old topology options to avoid breaking things between releases +// Related to https://github.com/weaveworks/scope/pull/2404 +function detectOldOptions(topologyOptions) { + let bad = false; + each(topologyOptions, (topology) => { + each(topology, (option) => { + if (typeof option === 'string') { + bad = true; + } + }); + }); + return bad; +} + +export function getRouter(initialState) { + return (dispatch, getState) => { + // strip any trailing '/'s. + page.base(window.location.pathname.replace(/\/$/, '')); + + page('/', () => { + // recover from storage state on empty URL + const storageState = storageGet(STORAGE_STATE_KEY); + if (storageState && isStoreViewStateEnabled(getState())) { + const parsedState = JSON.parse(decodeURL(storageState)); + const dirtyOptions = detectOldOptions(parsedState.topologyOptions); + if (dirtyOptions) { + dispatch(route(initialState)); + } else { + const mergedState = Object.assign(initialState, parsedState); + // push storage state to URL + window.location.hash = `!/state/${stableStringify(mergedState)}`; + dispatch(route(mergedState)); + } + } else { + dispatch(route(initialState)); + } + }); + + page('/state/:state', (ctx) => { + const state = JSON.parse(decodeURL(ctx.params.state)); + const dirtyOptions = detectOldOptions(state.topologyOptions); + const nextState = dirtyOptions ? initialState : state; + + // back up state in storage and redirect + if (isStoreViewStateEnabled(getState())) { + storageSet(STORAGE_STATE_KEY, encodeURL(stableStringify(state))); + } + + dispatch(route(nextState)); + }); + + return page; + }; +} diff --git a/client/app/scripts/utils/router-utils.js b/client/app/scripts/utils/router-utils.js index df582cd24..aa339ed52 100644 --- a/client/app/scripts/utils/router-utils.js +++ b/client/app/scripts/utils/router-utils.js @@ -1,13 +1,10 @@ import page from 'page'; import stableStringify from 'json-stable-stringify'; import { fromJS, is as isDeepEqual } from 'immutable'; -import { - each, omit, omitBy, isEmpty -} from 'lodash'; +import { omit, omitBy, isEmpty } from 'lodash'; -import { route } from '../actions/app-actions'; import { hashDifferenceDeep } from './hash-utils'; -import { storageGet, storageSet } from './storage-utils'; +import { storageSet } from './storage-utils'; import { getDefaultTopologyOptions, initialState as initialRootState } from '../reducers/root'; @@ -19,9 +16,9 @@ const SLASH = '/'; const SLASH_REPLACEMENT = ''; const PERCENT = '%'; const PERCENT_REPLACEMENT = ''; -const STORAGE_STATE_KEY = 'scopeViewState'; +export const STORAGE_STATE_KEY = 'scopeViewState'; -function encodeURL(url) { +export function encodeURL(url) { return url .replace(new RegExp(PERCENT, 'g'), PERCENT_REPLACEMENT) .replace(new RegExp(SLASH, 'g'), SLASH_REPLACEMENT); @@ -43,7 +40,7 @@ export function clearStoredViewState() { storageSet(STORAGE_STATE_KEY, ''); } -function isStoreViewStateEnabled(state) { +export function isStoreViewStateEnabled(state) { return state.get('storeViewState'); } @@ -137,59 +134,3 @@ export function updateRoute(getState) { page.show(`/state/${stateUrl}`, state, dispatch); } } - -// Temporarily detect old topology options to avoid breaking things between releases -// Related to https://github.com/weaveworks/scope/pull/2404 -function detectOldOptions(topologyOptions) { - let bad = false; - each(topologyOptions, (topology) => { - each(topology, (option) => { - if (typeof option === 'string') { - bad = true; - } - }); - }); - return bad; -} - - -export function getRouter(initialState) { - return (dispatch, getState) => { - // strip any trailing '/'s. - page.base(window.location.pathname.replace(/\/$/, '')); - - page('/', () => { - // recover from storage state on empty URL - const storageState = storageGet(STORAGE_STATE_KEY); - if (storageState && isStoreViewStateEnabled(getState())) { - const parsedState = JSON.parse(decodeURL(storageState)); - const dirtyOptions = detectOldOptions(parsedState.topologyOptions); - if (dirtyOptions) { - dispatch(route(initialState)); - } else { - const mergedState = Object.assign(initialState, parsedState); - // push storage state to URL - window.location.hash = `!/state/${stableStringify(mergedState)}`; - dispatch(route(mergedState)); - } - } else { - dispatch(route(initialState)); - } - }); - - page('/state/:state', (ctx) => { - const state = JSON.parse(decodeURL(ctx.params.state)); - const dirtyOptions = detectOldOptions(state.topologyOptions); - const nextState = dirtyOptions ? initialState : state; - - // back up state in storage and redirect - if (isStoreViewStateEnabled(getState())) { - storageSet(STORAGE_STATE_KEY, encodeURL(stableStringify(state))); - } - - dispatch(route(nextState)); - }); - - return page; - }; -} From 478e3257550892c70dc037ae8830228ebfe9e7df Mon Sep 17 00:00:00 2001 From: Filip Barl Date: Fri, 2 Aug 2019 20:02:30 +0200 Subject: [PATCH 14/14] Resolved dependency cycle between actions and web utils --- client/app/scripts/actions/app-actions.js | 371 +---------- client/app/scripts/actions/request-actions.js | 608 ++++++++++++++++++ client/app/scripts/charts/node-container.js | 3 +- client/app/scripts/charts/nodes-grid.js | 3 +- client/app/scripts/components/app.js | 12 +- client/app/scripts/components/node-details.js | 2 +- .../node-details-control-button.js | 2 +- .../node-details-relatives-link.js | 2 +- .../node-details-table-node-link.js | 2 +- .../node-resources-metric-box.js | 2 +- client/app/scripts/components/search.js | 5 +- client/app/scripts/components/terminal.js | 3 +- client/app/scripts/components/time-control.js | 2 +- .../scripts/components/time-travel-wrapper.js | 2 +- client/app/scripts/components/topologies.js | 2 +- .../scripts/components/topology-options.js | 2 +- .../scripts/components/view-mode-selector.js | 3 +- client/app/scripts/router.js | 2 +- client/app/scripts/utils/web-api-utils.js | 223 +------ 19 files changed, 644 insertions(+), 607 deletions(-) create mode 100644 client/app/scripts/actions/request-actions.js diff --git a/client/app/scripts/actions/app-actions.js b/client/app/scripts/actions/app-actions.js index ccc307e51..ec5bb0acc 100644 --- a/client/app/scripts/actions/app-actions.js +++ b/client/app/scripts/actions/app-actions.js @@ -1,45 +1,19 @@ -import debug from 'debug'; -import { fromJS } from 'immutable'; - import ActionTypes from '../constants/action-types'; import { saveGraph } from '../utils/file-utils'; import { clearStoredViewState, updateRoute } from '../utils/router-utils'; -import { - doRequest, - getApiPath, - getAllNodes, - getResourceViewNodesSnapshot, - getNodeDetails, - getTopologies, - deletePipe, - stopPolling, - teardownWebsockets, - getNodes, -} from '../utils/web-api-utils'; import { isPausedSelector } from '../selectors/time-travel'; import { - availableMetricTypesSelector, nextPinnedMetricTypeSelector, previousPinnedMetricTypeSelector, - pinnedMetricSelector, } from '../selectors/node-metric'; -import { - isResourceViewModeSelector, - resourceViewAvailableSelector, -} from '../selectors/topology'; +import { isResourceViewModeSelector } from '../selectors/topology'; import { GRAPH_VIEW_MODE, TABLE_VIEW_MODE, - RESOURCE_VIEW_MODE, } from '../constants/naming'; -let controlErrorTimer = 0; - -const log = debug('scope:app-actions'); - - export function showHelp() { return { type: ActionTypes.SHOW_HELP }; } @@ -184,41 +158,10 @@ export function updateSearch(searchQuery = '', pinnedSearches = []) { }; } -export function focusSearch() { - return (dispatch, getState) => { - dispatch({ type: ActionTypes.FOCUS_SEARCH }); - // update nodes cache to allow search across all topologies, - // wait a second until animation is over - // NOTE: This will cause matching recalculation (and rerendering) - // of all the nodes in the topology, instead applying it only on - // the nodes delta. The solution would be to implement deeper - // search selectors with per-node caching instead of per-topology. - setTimeout(() => { - getAllNodes(getState(), dispatch); - }, 1200); - }; -} - export function blurSearch() { return { type: ActionTypes.BLUR_SEARCH }; } -export function changeTopologyOption(option, value, topologyId, addOrRemove) { - return (dispatch, getState) => { - dispatch({ - addOrRemove, - option, - topologyId, - type: ActionTypes.CHANGE_TOPOLOGY_OPTION, - value - }); - updateRoute(getState); - // update all request workers with new options - getTopologies(getState, dispatch); - getNodes(getState, dispatch); - }; -} - export function clickBackground() { return (dispatch, getState) => { dispatch({ @@ -228,18 +171,6 @@ export function clickBackground() { }; } -export function clickCloseDetails(nodeId) { - return (dispatch, getState) => { - dispatch({ - nodeId, - type: ActionTypes.CLICK_CLOSE_DETAILS - }); - // Pull the most recent details for the next details panel that comes into focus. - getNodeDetails(getState, dispatch); - updateRoute(getState); - }; -} - export function closeTerminal(pipeId) { return (dispatch, getState) => { dispatch({ @@ -300,102 +231,6 @@ export function setTableView() { }; } -export function setResourceView() { - return (dispatch, getState) => { - if (resourceViewAvailableSelector(getState())) { - dispatch({ - type: ActionTypes.SET_VIEW_MODE, - viewMode: RESOURCE_VIEW_MODE, - }); - // Pin the first metric if none of the visible ones is pinned. - const state = getState(); - if (!pinnedMetricSelector(state)) { - const firstAvailableMetricType = availableMetricTypesSelector(state).first(); - dispatch(pinMetric(firstAvailableMetricType)); - } - getResourceViewNodesSnapshot(getState(), dispatch); - updateRoute(getState); - } - }; -} - -export function clickNode(nodeId, label, origin, topologyId = null) { - return (dispatch, getState) => { - dispatch({ - label, - nodeId, - origin, - topologyId, - type: ActionTypes.CLICK_NODE, - }); - updateRoute(getState); - getNodeDetails(getState, dispatch); - }; -} - -export function pauseTimeAtNow() { - return (dispatch, getState) => { - dispatch({ - type: ActionTypes.PAUSE_TIME_AT_NOW - }); - updateRoute(getState); - if (!getState().get('nodesLoaded')) { - getNodes(getState, dispatch); - if (isResourceViewModeSelector(getState())) { - getResourceViewNodesSnapshot(getState(), dispatch); - } - } - }; -} - -export function clickRelative(nodeId, topologyId, label, origin) { - return (dispatch, getState) => { - dispatch({ - label, - nodeId, - origin, - topologyId, - type: ActionTypes.CLICK_RELATIVE - }); - updateRoute(getState); - getNodeDetails(getState, dispatch); - }; -} - -function updateTopology(dispatch, getState) { - const state = getState(); - // If we're in the resource view, get the snapshot of all the relevant node topologies. - if (isResourceViewModeSelector(state)) { - getResourceViewNodesSnapshot(state, dispatch); - } - updateRoute(getState); - // NOTE: This is currently not needed for our static resource - // view, but we'll need it here later and it's simpler to just - // keep it than to redo the nodes delta updating logic. - getNodes(getState, dispatch); -} - -export function clickShowTopologyForNode(topologyId, nodeId) { - return (dispatch, getState) => { - dispatch({ - nodeId, - topologyId, - type: ActionTypes.CLICK_SHOW_TOPOLOGY_FOR_NODE - }); - updateTopology(dispatch, getState); - }; -} - -export function clickTopology(topologyId) { - return (dispatch, getState) => { - dispatch({ - topologyId, - type: ActionTypes.CLICK_TOPOLOGY - }); - updateTopology(dispatch, getState); - }; -} - export function cacheZoomState(zoomState) { return { type: ActionTypes.CACHE_ZOOM_STATE, @@ -520,23 +355,6 @@ export function receiveNodesDelta(delta) { }; } -export function resumeTime() { - return (dispatch, getState) => { - if (isPausedSelector(getState())) { - dispatch({ - type: ActionTypes.RESUME_TIME - }); - updateRoute(getState); - // After unpausing, all of the following calls will re-activate polling. - getTopologies(getState, dispatch); - getNodes(getState, dispatch, true); - if (isResourceViewModeSelector(getState())) { - getResourceViewNodesSnapshot(getState(), dispatch); - } - } - }; -} - export function receiveNodes(nodes) { return { nodes, @@ -544,26 +362,6 @@ export function receiveNodes(nodes) { }; } -export function jumpToTime(timestamp) { - return (dispatch, getState) => { - dispatch({ - timestamp, - type: ActionTypes.JUMP_TO_TIME, - }); - updateRoute(getState); - getTopologies(getState, dispatch); - if (!getState().get('nodesLoaded')) { - getNodes(getState, dispatch); - if (isResourceViewModeSelector(getState())) { - getResourceViewNodesSnapshot(getState(), dispatch); - } - } else { - // Get most recent details before freezing the state. - getNodeDetails(getState, dispatch); - } - }; -} - export function receiveNodesForTopology(nodes, topologyId) { return { nodes, @@ -572,53 +370,6 @@ export function receiveNodesForTopology(nodes, topologyId) { }; } -export function receiveTopologies(topologies) { - return (dispatch, getState) => { - const firstLoad = !getState().get('topologiesLoaded'); - dispatch({ - topologies, - type: ActionTypes.RECEIVE_TOPOLOGIES - }); - getNodes(getState, dispatch); - // Populate search matches on first load - const state = getState(); - // Fetch all the relevant nodes once on first load - if (firstLoad && isResourceViewModeSelector(state)) { - getResourceViewNodesSnapshot(state, dispatch); - } - }; -} - -export function receiveApiDetails(apiDetails) { - return (dispatch, getState) => { - const isFirstTime = !getState().get('version'); - const pausedAt = getState().get('pausedAt'); - - dispatch({ - capabilities: fromJS(apiDetails.capabilities || {}), - hostname: apiDetails.hostname, - newVersion: apiDetails.newVersion, - plugins: apiDetails.plugins, - type: ActionTypes.RECEIVE_API_DETAILS, - version: apiDetails.version, - }); - - // On initial load either start time travelling at the pausedAt timestamp - // (if it was given as URL param) if time travelling is enabled, otherwise - // simply pause at the present time which is arguably the next best thing - // we could do. - // NOTE: We can't make this decision before API details are received because - // we have no prior info on whether time travel would be available. - if (isFirstTime && pausedAt) { - if (apiDetails.capabilities && apiDetails.capabilities.historic_reports) { - dispatch(jumpToTime(pausedAt)); - } else { - dispatch(pauseTimeAtNow()); - } - } - }; -} - export function receiveControlNodeRemoved(nodeId) { return (dispatch, getState) => { dispatch({ @@ -639,34 +390,6 @@ export function receiveControlPipeFromParams(pipeId, rawTty, resizeTtyControl) { }; } -export function receiveControlPipe(pipeId, nodeId, rawTty, resizeTtyControl, control) { - return (dispatch, getState) => { - const state = getState(); - if (state.get('nodeDetails').last() - && nodeId !== state.get('nodeDetails').last().id) { - log('Node was deselected before we could set up control!'); - deletePipe(pipeId, dispatch); - return; - } - - const controlPipe = state.get('controlPipes').last(); - if (controlPipe && controlPipe.get('id') !== pipeId) { - deletePipe(controlPipe.get('id'), dispatch); - } - - dispatch({ - control, - nodeId, - pipeId, - rawTty, - resizeTtyControl, - type: ActionTypes.RECEIVE_CONTROL_PIPE - }); - - updateRoute(getState); - }; -} - export function receiveControlPipeStatus(pipeId, status) { return { pipeId, @@ -675,53 +398,6 @@ export function receiveControlPipeStatus(pipeId, status) { }; } -function doControlRequest(nodeId, control, dispatch) { - clearTimeout(controlErrorTimer); - const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/` - + `${encodeURIComponent(control.nodeId)}/${control.id}`; - doRequest({ - error: (err) => { - dispatch(receiveControlError(nodeId, err.response)); - controlErrorTimer = setTimeout(() => { - dispatch(clearControlError(nodeId)); - }, 10000); - }, - method: 'POST', - success: (res) => { - dispatch(receiveControlSuccess(nodeId)); - if (res) { - if (res.pipe) { - dispatch(blurSearch()); - const resizeTtyControl = res.resize_tty_control - && { id: res.resize_tty_control, nodeId: control.nodeId, probeId: control.probeId }; - dispatch(receiveControlPipe( - res.pipe, - nodeId, - res.raw_tty, - resizeTtyControl, - control - )); - } - if (res.removedNode) { - dispatch(receiveControlNodeRemoved(nodeId)); - } - } - }, - url - }); -} - -export function doControl(nodeId, control) { - return (dispatch) => { - dispatch({ - control, - nodeId, - type: ActionTypes.DO_CONTROL - }); - doControlRequest(nodeId, control, dispatch); - }; -} - export function receiveError(errorUrl) { return { errorUrl, @@ -747,41 +423,6 @@ export function setContrastMode(enabled) { }; } -export function getTopologiesWithInitialPoll() { - return (dispatch, getState) => { - getTopologies(getState, dispatch, true); - }; -} - -export function route(urlState) { - return (dispatch, getState) => { - dispatch({ - state: urlState, - type: ActionTypes.ROUTE_TOPOLOGY - }); - // Handle Time Travel state update through separate actions as it's more complex. - // This is mostly to handle switching contexts Explore <-> Monitor in WC while - // the timestamp keeps changing - e.g. if we were Time Travelling in Scope and - // then went live in Monitor, switching back to Explore should properly close - // the Time Travel etc, not just update the pausedAt state directly. - if (!urlState.pausedAt) { - dispatch(resumeTime()); - } else { - dispatch(jumpToTime(urlState.pausedAt)); - } - // update all request workers with new options - getTopologies(getState, dispatch); - getNodes(getState, dispatch); - // If we are landing on the resource view page, we need to fetch not only all the - // nodes for the current topology, but also the nodes of all the topologies that make - // the layers in the resource view. - const state = getState(); - if (isResourceViewModeSelector(state)) { - getResourceViewNodesSnapshot(state, dispatch); - } - }; -} - export function resetLocalViewState() { return (dispatch) => { dispatch({ type: ActionTypes.RESET_LOCAL_VIEW_STATE }); @@ -807,16 +448,6 @@ export function changeInstance() { }; } -export function shutdown() { - return (dispatch) => { - stopPolling(); - teardownWebsockets(); - dispatch({ - type: ActionTypes.SHUTDOWN - }); - }; -} - export function setMonitorState(monitor) { return { monitor, diff --git a/client/app/scripts/actions/request-actions.js b/client/app/scripts/actions/request-actions.js new file mode 100644 index 000000000..82a7e7d9f --- /dev/null +++ b/client/app/scripts/actions/request-actions.js @@ -0,0 +1,608 @@ +/* + +This file consists of functions that both dispatch actions to Redux and also make API requests. + +TODO: Refactor all the methods below so that the split between actions and +requests is more clear, and make user components make explicit calls to requests +and dispatch actions when handling request promises. + +*/ +import debug from 'debug'; +import { fromJS } from 'immutable'; + +import ActionTypes from '../constants/action-types'; +import { RESOURCE_VIEW_MODE } from '../constants/naming'; +import { + API_REFRESH_INTERVAL, + TOPOLOGY_REFRESH_INTERVAL, +} from '../constants/timer'; +import { updateRoute } from '../utils/router-utils'; +import { getCurrentTopologyUrl } from '../utils/topology-utils'; +import { + doRequest, + getApiPath, + getAllNodes, + getNodesOnce, + deletePipe, + getNodeDetails, + getResourceViewNodesSnapshot, + topologiesUrl, + buildWebsocketUrl, +} from '../utils/web-api-utils'; +import { + availableMetricTypesSelector, + pinnedMetricSelector, +} from '../selectors/node-metric'; +import { + isResourceViewModeSelector, + resourceViewAvailableSelector, + activeTopologyOptionsSelector, +} from '../selectors/topology'; +import { isPausedSelector } from '../selectors/time-travel'; + +import { + receiveControlNodeRemoved, + receiveControlPipeStatus, + receiveControlSuccess, + receiveControlError, + receiveError, + pinMetric, + openWebsocket, + closeWebsocket, + receiveNodesDelta, + clearControlError, + blurSearch, +} from './app-actions'; + + +const log = debug('scope:app-actions'); +const reconnectTimerInterval = 5000; +const FIRST_RENDER_TOO_LONG_THRESHOLD = 100; // ms + +let socket; +let topologyTimer = 0; +let controlErrorTimer = 0; +let reconnectTimer = 0; +let apiDetailsTimer = 0; +let continuePolling = true; +let firstMessageOnWebsocketAt = null; +let createWebsocketAt = null; +let currentUrl = null; + +function createWebsocket(websocketUrl, getState, dispatch) { + if (socket) { + socket.onclose = null; + socket.onerror = null; + socket.close(); + // onclose() is not called, but that's fine since we're opening a new one + // right away + } + + // profiling + createWebsocketAt = new Date(); + firstMessageOnWebsocketAt = null; + + socket = new WebSocket(websocketUrl); + + socket.onopen = () => { + log(`Opening websocket to ${websocketUrl}`); + dispatch(openWebsocket()); + }; + + socket.onclose = () => { + clearTimeout(reconnectTimer); + log(`Closing websocket to ${websocketUrl}`, socket.readyState); + socket = null; + dispatch(closeWebsocket()); + + if (continuePolling && !isPausedSelector(getState())) { + reconnectTimer = setTimeout(() => { + createWebsocket(websocketUrl, getState, dispatch); + }, reconnectTimerInterval); + } + }; + + socket.onerror = () => { + log(`Error in websocket to ${websocketUrl}`); + dispatch(receiveError(websocketUrl)); + }; + + socket.onmessage = (event) => { + const msg = JSON.parse(event.data); + dispatch(receiveNodesDelta(msg)); + + // profiling (receiveNodesDelta triggers synchronous render) + if (!firstMessageOnWebsocketAt) { + firstMessageOnWebsocketAt = new Date(); + const timeToFirstMessage = firstMessageOnWebsocketAt - createWebsocketAt; + if (timeToFirstMessage > FIRST_RENDER_TOO_LONG_THRESHOLD) { + log( + 'Time (ms) to first nodes render after websocket was created', + firstMessageOnWebsocketAt - createWebsocketAt + ); + } + } + }; +} + +function teardownWebsockets() { + clearTimeout(reconnectTimer); + if (socket) { + socket.onerror = null; + socket.onclose = null; + socket.onmessage = null; + socket.onopen = null; + socket.close(); + socket = null; + currentUrl = null; + } +} + +function updateWebsocketChannel(getState, dispatch, forceRequest) { + const topologyUrl = getCurrentTopologyUrl(getState()); + const topologyOptions = activeTopologyOptionsSelector(getState()); + const websocketUrl = buildWebsocketUrl(topologyUrl, topologyOptions, getState()); + // Only recreate websocket if url changed or if forced (weave cloud instance reload); + const isNewUrl = websocketUrl !== currentUrl; + // `topologyUrl` can be undefined initially, so only create a socket if it is truthy + // and no socket exists, or if we get a new url. + if (topologyUrl && (!socket || isNewUrl || forceRequest)) { + createWebsocket(websocketUrl, getState, dispatch); + currentUrl = websocketUrl; + } +} + +function getNodes(getState, dispatch, forceRequest = false) { + if (isPausedSelector(getState())) { + getNodesOnce(getState, dispatch); + } else { + updateWebsocketChannel(getState, dispatch, forceRequest); + } + getNodeDetails(getState, dispatch); +} + +export function pauseTimeAtNow() { + return (dispatch, getState) => { + dispatch({ + type: ActionTypes.PAUSE_TIME_AT_NOW + }); + updateRoute(getState); + if (!getState().get('nodesLoaded')) { + getNodes(getState, dispatch); + if (isResourceViewModeSelector(getState())) { + getResourceViewNodesSnapshot(getState(), dispatch); + } + } + }; +} + +function receiveTopologies(topologies) { + return (dispatch, getState) => { + const firstLoad = !getState().get('topologiesLoaded'); + dispatch({ + topologies, + type: ActionTypes.RECEIVE_TOPOLOGIES + }); + getNodes(getState, dispatch); + // Populate search matches on first load + const state = getState(); + // Fetch all the relevant nodes once on first load + if (firstLoad && isResourceViewModeSelector(state)) { + getResourceViewNodesSnapshot(state, dispatch); + } + }; +} + +function getTopologiesOnce(getState, dispatch) { + const url = topologiesUrl(getState()); + doRequest({ + error: (req) => { + log(`Error in topology request: ${req.responseText}`); + dispatch(receiveError(url)); + }, + success: (res) => { + dispatch(receiveTopologies(res)); + }, + url + }); +} + +function pollTopologies(getState, dispatch, initialPoll = false) { + // Used to resume polling when navigating between pages in Weave Cloud. + continuePolling = initialPoll === true ? true : continuePolling; + clearTimeout(topologyTimer); + // NOTE: getState is called every time to make sure the up-to-date state is used. + const url = topologiesUrl(getState()); + doRequest({ + error: (req) => { + log(`Error in topology request: ${req.responseText}`); + dispatch(receiveError(url)); + // Only retry in stand-alone mode + if (continuePolling && !isPausedSelector(getState())) { + topologyTimer = setTimeout(() => { + pollTopologies(getState, dispatch); + }, TOPOLOGY_REFRESH_INTERVAL); + } + }, + success: (res) => { + if (continuePolling && !isPausedSelector(getState())) { + dispatch(receiveTopologies(res)); + topologyTimer = setTimeout(() => { + pollTopologies(getState, dispatch); + }, TOPOLOGY_REFRESH_INTERVAL); + } + }, + url + }); +} + +function getTopologies(getState, dispatch, forceRequest) { + if (isPausedSelector(getState())) { + getTopologiesOnce(getState, dispatch); + } else { + pollTopologies(getState, dispatch, forceRequest); + } +} + +export function jumpToTime(timestamp) { + return (dispatch, getState) => { + dispatch({ + timestamp, + type: ActionTypes.JUMP_TO_TIME, + }); + updateRoute(getState); + getTopologies(getState, dispatch); + if (!getState().get('nodesLoaded')) { + getNodes(getState, dispatch); + if (isResourceViewModeSelector(getState())) { + getResourceViewNodesSnapshot(getState(), dispatch); + } + } else { + // Get most recent details before freezing the state. + getNodeDetails(getState, dispatch); + } + }; +} + +export function receiveApiDetails(apiDetails) { + return (dispatch, getState) => { + const isFirstTime = !getState().get('version'); + const pausedAt = getState().get('pausedAt'); + + dispatch({ + capabilities: fromJS(apiDetails.capabilities || {}), + hostname: apiDetails.hostname, + newVersion: apiDetails.newVersion, + plugins: apiDetails.plugins, + type: ActionTypes.RECEIVE_API_DETAILS, + version: apiDetails.version, + }); + + // On initial load either start time travelling at the pausedAt timestamp + // (if it was given as URL param) if time travelling is enabled, otherwise + // simply pause at the present time which is arguably the next best thing + // we could do. + // NOTE: We can't make this decision before API details are received because + // we have no prior info on whether time travel would be available. + if (isFirstTime && pausedAt) { + if (apiDetails.capabilities && apiDetails.capabilities.historic_reports) { + dispatch(jumpToTime(pausedAt)); + } else { + dispatch(pauseTimeAtNow()); + } + } + }; +} + +export function getApiDetails(dispatch) { + clearTimeout(apiDetailsTimer); + const url = `${getApiPath()}/api`; + doRequest({ + error: (req) => { + log(`Error in api details request: ${req.responseText}`); + receiveError(url); + if (continuePolling) { + apiDetailsTimer = setTimeout(() => { + getApiDetails(dispatch); + }, API_REFRESH_INTERVAL / 2); + } + }, + success: (res) => { + dispatch(receiveApiDetails(res)); + if (continuePolling) { + apiDetailsTimer = setTimeout(() => { + getApiDetails(dispatch); + }, API_REFRESH_INTERVAL); + } + }, + url + }); +} + +function stopPolling() { + clearTimeout(apiDetailsTimer); + clearTimeout(topologyTimer); + continuePolling = false; +} + +export function focusSearch() { + return (dispatch, getState) => { + dispatch({ type: ActionTypes.FOCUS_SEARCH }); + // update nodes cache to allow search across all topologies, + // wait a second until animation is over + // NOTE: This will cause matching recalculation (and rerendering) + // of all the nodes in the topology, instead applying it only on + // the nodes delta. The solution would be to implement deeper + // search selectors with per-node caching instead of per-topology. + setTimeout(() => { + getAllNodes(getState(), dispatch); + }, 1200); + }; +} + +export function getPipeStatus(pipeId, dispatch) { + const url = `${getApiPath()}/api/pipe/${encodeURIComponent(pipeId)}/check`; + doRequest({ + complete: (res) => { + const status = { + 204: 'PIPE_ALIVE', + 404: 'PIPE_DELETED' + }[res.status]; + + if (!status) { + log('Unexpected pipe status:', res.status); + return; + } + + dispatch(receiveControlPipeStatus(pipeId, status)); + }, + method: 'GET', + url + }); +} + +export function receiveControlPipe(pipeId, nodeId, rawTty, resizeTtyControl, control) { + return (dispatch, getState) => { + const state = getState(); + if (state.get('nodeDetails').last() + && nodeId !== state.get('nodeDetails').last().id) { + log('Node was deselected before we could set up control!'); + deletePipe(pipeId, dispatch); + return; + } + + const controlPipe = state.get('controlPipes').last(); + if (controlPipe && controlPipe.get('id') !== pipeId) { + deletePipe(controlPipe.get('id'), dispatch); + } + + dispatch({ + control, + nodeId, + pipeId, + rawTty, + resizeTtyControl, + type: ActionTypes.RECEIVE_CONTROL_PIPE + }); + + updateRoute(getState); + }; +} + +function doControlRequest(nodeId, control, dispatch) { + clearTimeout(controlErrorTimer); + const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/` + + `${encodeURIComponent(control.nodeId)}/${control.id}`; + doRequest({ + error: (err) => { + dispatch(receiveControlError(nodeId, err.response)); + controlErrorTimer = setTimeout(() => { + dispatch(clearControlError(nodeId)); + }, 10000); + }, + method: 'POST', + success: (res) => { + dispatch(receiveControlSuccess(nodeId)); + if (res) { + if (res.pipe) { + dispatch(blurSearch()); + const resizeTtyControl = res.resize_tty_control + && { id: res.resize_tty_control, nodeId: control.nodeId, probeId: control.probeId }; + dispatch(receiveControlPipe( + res.pipe, + nodeId, + res.raw_tty, + resizeTtyControl, + control + )); + } + if (res.removedNode) { + dispatch(receiveControlNodeRemoved(nodeId)); + } + } + }, + url + }); +} + +export function doControl(nodeId, control) { + return (dispatch) => { + dispatch({ + control, + nodeId, + type: ActionTypes.DO_CONTROL + }); + doControlRequest(nodeId, control, dispatch); + }; +} + +export function shutdown() { + return (dispatch) => { + stopPolling(); + teardownWebsockets(); + dispatch({ + type: ActionTypes.SHUTDOWN + }); + }; +} + +export function setResourceView() { + return (dispatch, getState) => { + if (resourceViewAvailableSelector(getState())) { + dispatch({ + type: ActionTypes.SET_VIEW_MODE, + viewMode: RESOURCE_VIEW_MODE, + }); + // Pin the first metric if none of the visible ones is pinned. + const state = getState(); + if (!pinnedMetricSelector(state)) { + const firstAvailableMetricType = availableMetricTypesSelector(state).first(); + dispatch(pinMetric(firstAvailableMetricType)); + } + getResourceViewNodesSnapshot(getState(), dispatch); + updateRoute(getState); + } + }; +} + +export function changeTopologyOption(option, value, topologyId, addOrRemove) { + return (dispatch, getState) => { + dispatch({ + addOrRemove, + option, + topologyId, + type: ActionTypes.CHANGE_TOPOLOGY_OPTION, + value + }); + updateRoute(getState); + // update all request workers with new options + getTopologies(getState, dispatch); + getNodes(getState, dispatch); + }; +} + +export function getTopologiesWithInitialPoll() { + return (dispatch, getState) => { + getTopologies(getState, dispatch, true); + }; +} + +export function resumeTime() { + return (dispatch, getState) => { + if (isPausedSelector(getState())) { + dispatch({ + type: ActionTypes.RESUME_TIME + }); + updateRoute(getState); + // After unpausing, all of the following calls will re-activate polling. + getTopologies(getState, dispatch); + getNodes(getState, dispatch, true); + if (isResourceViewModeSelector(getState())) { + getResourceViewNodesSnapshot(getState(), dispatch); + } + } + }; +} + +export function route(urlState) { + return (dispatch, getState) => { + dispatch({ + state: urlState, + type: ActionTypes.ROUTE_TOPOLOGY + }); + // Handle Time Travel state update through separate actions as it's more complex. + // This is mostly to handle switching contexts Explore <-> Monitor in WC while + // the timestamp keeps changing - e.g. if we were Time Travelling in Scope and + // then went live in Monitor, switching back to Explore should properly close + // the Time Travel etc, not just update the pausedAt state directly. + if (!urlState.pausedAt) { + dispatch(resumeTime()); + } else { + dispatch(jumpToTime(urlState.pausedAt)); + } + // update all request workers with new options + getTopologies(getState, dispatch); + getNodes(getState, dispatch); + // If we are landing on the resource view page, we need to fetch not only all the + // nodes for the current topology, but also the nodes of all the topologies that make + // the layers in the resource view. + const state = getState(); + if (isResourceViewModeSelector(state)) { + getResourceViewNodesSnapshot(state, dispatch); + } + }; +} + +export function clickCloseDetails(nodeId) { + return (dispatch, getState) => { + dispatch({ + nodeId, + type: ActionTypes.CLICK_CLOSE_DETAILS + }); + // Pull the most recent details for the next details panel that comes into focus. + getNodeDetails(getState, dispatch); + updateRoute(getState); + }; +} + +export function clickNode(nodeId, label, origin, topologyId = null) { + return (dispatch, getState) => { + dispatch({ + label, + nodeId, + origin, + topologyId, + type: ActionTypes.CLICK_NODE, + }); + updateRoute(getState); + getNodeDetails(getState, dispatch); + }; +} + +export function clickRelative(nodeId, topologyId, label, origin) { + return (dispatch, getState) => { + dispatch({ + label, + nodeId, + origin, + topologyId, + type: ActionTypes.CLICK_RELATIVE + }); + updateRoute(getState); + getNodeDetails(getState, dispatch); + }; +} + +function updateTopology(dispatch, getState) { + const state = getState(); + // If we're in the resource view, get the snapshot of all the relevant node topologies. + if (isResourceViewModeSelector(state)) { + getResourceViewNodesSnapshot(state, dispatch); + } + updateRoute(getState); + // NOTE: This is currently not needed for our static resource + // view, but we'll need it here later and it's simpler to just + // keep it than to redo the nodes delta updating logic. + getNodes(getState, dispatch); +} + +export function clickShowTopologyForNode(topologyId, nodeId) { + return (dispatch, getState) => { + dispatch({ + nodeId, + topologyId, + type: ActionTypes.CLICK_SHOW_TOPOLOGY_FOR_NODE + }); + updateTopology(dispatch, getState); + }; +} + +export function clickTopology(topologyId) { + return (dispatch, getState) => { + dispatch({ + topologyId, + type: ActionTypes.CLICK_TOPOLOGY + }); + updateTopology(dispatch, getState); + }; +} diff --git a/client/app/scripts/charts/node-container.js b/client/app/scripts/charts/node-container.js index 636412465..c7dd15840 100644 --- a/client/app/scripts/charts/node-container.js +++ b/client/app/scripts/charts/node-container.js @@ -7,7 +7,8 @@ import { getMetricValue, getMetricColor, } from '../utils/metric-utils'; -import { clickNode, enterNode, leaveNode } from '../actions/app-actions'; +import { clickNode } from '../actions/request-actions'; +import { enterNode, leaveNode } from '../actions/app-actions'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { getNodeColor } from '../utils/color-utils'; import MatchedResults from '../components/matched-results'; diff --git a/client/app/scripts/charts/nodes-grid.js b/client/app/scripts/charts/nodes-grid.js index 9d78a9158..8cd2c6d6c 100644 --- a/client/app/scripts/charts/nodes-grid.js +++ b/client/app/scripts/charts/nodes-grid.js @@ -6,7 +6,8 @@ import { List as makeList, Map as makeMap } from 'immutable'; import capitalize from 'lodash/capitalize'; import NodeDetailsTable from '../components/node-details/node-details-table'; -import { clickNode, sortOrderChanged } from '../actions/app-actions'; +import { clickNode } from '../actions/request-actions'; +import { sortOrderChanged } from '../actions/app-actions'; import { shownNodesSelector } from '../selectors/node-filters'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { findTopologyById } from '../utils/topology-utils'; diff --git a/client/app/scripts/components/app.js b/client/app/scripts/components/app.js index 278bd6f56..b9a4ebc74 100644 --- a/client/app/scripts/components/app.js +++ b/client/app/scripts/components/app.js @@ -18,9 +18,7 @@ import Status from './status'; import Topologies from './topologies'; import TopologyOptions from './topology-options'; import Overlay from './overlay'; -import { getApiDetails } from '../utils/web-api-utils'; import { - focusSearch, pinNextMetric, pinPreviousMetric, hitEsc, @@ -29,12 +27,16 @@ import { setGraphView, setMonitorState, setTableView, - setResourceView, setStoreViewState, - shutdown, setViewportDimensions, - getTopologiesWithInitialPoll, } from '../actions/app-actions'; +import { + focusSearch, + getApiDetails, + setResourceView, + getTopologiesWithInitialPoll, + shutdown, +} from '../actions/request-actions'; import Details from './details'; import Nodes from './nodes'; import TimeControl from './time-control'; diff --git a/client/app/scripts/components/node-details.js b/client/app/scripts/components/node-details.js index bd6f27221..bff3c839c 100644 --- a/client/app/scripts/components/node-details.js +++ b/client/app/scripts/components/node-details.js @@ -6,7 +6,7 @@ import { connect } from 'react-redux'; import { Map as makeMap } from 'immutable'; import { noop } from 'lodash'; -import { clickCloseDetails, clickShowTopologyForNode } from '../actions/app-actions'; +import { clickCloseDetails, clickShowTopologyForNode } from '../actions/request-actions'; import { brightenColor, getNeutralColor, getNodeColorDark } from '../utils/color-utils'; import { isGenericTable, isPropertyList } from '../utils/node-details-utils'; import { resetDocumentTitle, setDocumentTitle } from '../utils/title-utils'; diff --git a/client/app/scripts/components/node-details/node-details-control-button.js b/client/app/scripts/components/node-details/node-details-control-button.js index 8bca5fbb3..b79f8c304 100644 --- a/client/app/scripts/components/node-details/node-details-control-button.js +++ b/client/app/scripts/components/node-details/node-details-control-button.js @@ -4,7 +4,7 @@ import { isEmpty } from 'lodash'; import classNames from 'classnames'; import { trackAnalyticsEvent } from '../../utils/tracking-utils'; -import { doControl } from '../../actions/app-actions'; +import { doControl } from '../../actions/request-actions'; class NodeDetailsControlButton extends React.Component { constructor(props, context) { diff --git a/client/app/scripts/components/node-details/node-details-relatives-link.js b/client/app/scripts/components/node-details/node-details-relatives-link.js index 2750fb86e..77650b0c0 100644 --- a/client/app/scripts/components/node-details/node-details-relatives-link.js +++ b/client/app/scripts/components/node-details/node-details-relatives-link.js @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; -import { clickRelative } from '../../actions/app-actions'; +import { clickRelative } from '../../actions/request-actions'; import { trackAnalyticsEvent } from '../../utils/tracking-utils'; import MatchedText from '../matched-text'; diff --git a/client/app/scripts/components/node-details/node-details-table-node-link.js b/client/app/scripts/components/node-details/node-details-table-node-link.js index 45820b4d2..3d4f3f614 100644 --- a/client/app/scripts/components/node-details/node-details-table-node-link.js +++ b/client/app/scripts/components/node-details/node-details-table-node-link.js @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; -import { clickRelative } from '../../actions/app-actions'; +import { clickRelative } from '../../actions/request-actions'; import { trackAnalyticsEvent } from '../../utils/tracking-utils'; import { dismissRowClickProps } from '../../utils/dom-utils'; diff --git a/client/app/scripts/components/nodes-resources/node-resources-metric-box.js b/client/app/scripts/components/nodes-resources/node-resources-metric-box.js index 896c38de6..073afaee2 100644 --- a/client/app/scripts/components/nodes-resources/node-resources-metric-box.js +++ b/client/app/scripts/components/nodes-resources/node-resources-metric-box.js @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import theme from 'weaveworks-ui-components/lib/theme'; import NodeResourcesMetricBoxInfo from './node-resources-metric-box-info'; -import { clickNode } from '../../actions/app-actions'; +import { clickNode } from '../../actions/request-actions'; import { trackAnalyticsEvent } from '../../utils/tracking-utils'; import { applyTransform } from '../../utils/transform-utils'; import { RESOURCE_VIEW_MODE } from '../../constants/naming'; diff --git a/client/app/scripts/components/search.js b/client/app/scripts/components/search.js index 7b9840c19..bd0b09152 100644 --- a/client/app/scripts/components/search.js +++ b/client/app/scripts/components/search.js @@ -5,8 +5,11 @@ import { Search } from 'weaveworks-ui-components'; import styled from 'styled-components'; import { - blurSearch, focusSearch, updateSearch, toggleHelp + blurSearch, updateSearch, toggleHelp } from '../actions/app-actions'; +import { + focusSearch +} from '../actions/request-actions'; import { searchMatchCountByTopologySelector } from '../selectors/search'; import { isResourceViewModeSelector } from '../selectors/topology'; import { slugify } from '../utils/string-utils'; diff --git a/client/app/scripts/components/terminal.js b/client/app/scripts/components/terminal.js index e1e6c5a9f..5dda94fd7 100644 --- a/client/app/scripts/components/terminal.js +++ b/client/app/scripts/components/terminal.js @@ -8,10 +8,11 @@ import { Terminal as Term } from 'xterm'; import * as fit from 'xterm/lib/addons/fit/fit'; import { closeTerminal } from '../actions/app-actions'; +import { getPipeStatus } from '../actions/request-actions'; import { getNeutralColor } from '../utils/color-utils'; import { setDocumentTitle } from '../utils/title-utils'; import { - getPipeStatus, deletePipe, doResizeTty, getWebsocketUrl, basePath + deletePipe, doResizeTty, getWebsocketUrl, basePath } from '../utils/web-api-utils'; const log = debug('scope:terminal'); diff --git a/client/app/scripts/components/time-control.js b/client/app/scripts/components/time-control.js index 548aca887..b868599bf 100644 --- a/client/app/scripts/components/time-control.js +++ b/client/app/scripts/components/time-control.js @@ -4,7 +4,7 @@ import { connect } from 'react-redux'; import { TimestampTag } from 'weaveworks-ui-components'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; -import { pauseTimeAtNow, resumeTime } from '../actions/app-actions'; +import { pauseTimeAtNow, resumeTime } from '../actions/request-actions'; import { isPausedSelector, timeTravelSupportedSelector } from '../selectors/time-travel'; diff --git a/client/app/scripts/components/time-travel-wrapper.js b/client/app/scripts/components/time-travel-wrapper.js index ee749ece4..ba3c1fe4a 100644 --- a/client/app/scripts/components/time-travel-wrapper.js +++ b/client/app/scripts/components/time-travel-wrapper.js @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { TimeTravel } from 'weaveworks-ui-components'; -import { jumpToTime, resumeTime, pauseTimeAtNow } from '../actions/app-actions'; +import { jumpToTime, resumeTime, pauseTimeAtNow } from '../actions/request-actions'; class TimeTravelWrapper extends React.Component { handleLiveModeChange = (showingLive) => { diff --git a/client/app/scripts/components/topologies.js b/client/app/scripts/components/topologies.js index aa74286c3..617efe257 100644 --- a/client/app/scripts/components/topologies.js +++ b/client/app/scripts/components/topologies.js @@ -5,7 +5,7 @@ import classnames from 'classnames'; import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { searchMatchCountByTopologySelector } from '../selectors/search'; import { isResourceViewModeSelector } from '../selectors/topology'; -import { clickTopology } from '../actions/app-actions'; +import { clickTopology } from '../actions/request-actions'; function basicTopologyInfo(topology, searchMatchCount) { diff --git a/client/app/scripts/components/topology-options.js b/client/app/scripts/components/topology-options.js index 83c6a865b..bbc0c5f43 100644 --- a/client/app/scripts/components/topology-options.js +++ b/client/app/scripts/components/topology-options.js @@ -7,7 +7,7 @@ import { trackAnalyticsEvent } from '../utils/tracking-utils'; import { getCurrentTopologyOptions } from '../utils/topology-utils'; import { activeTopologyOptionsSelector } from '../selectors/topology'; import TopologyOptionAction from './topology-option-action'; -import { changeTopologyOption } from '../actions/app-actions'; +import { changeTopologyOption } from '../actions/request-actions'; class TopologyOptions extends React.Component { constructor(props, context) { diff --git a/client/app/scripts/components/view-mode-selector.js b/client/app/scripts/components/view-mode-selector.js index 370564719..7b183f385 100644 --- a/client/app/scripts/components/view-mode-selector.js +++ b/client/app/scripts/components/view-mode-selector.js @@ -3,7 +3,8 @@ import { connect } from 'react-redux'; import ViewModeButton from './view-mode-button'; import MetricSelector from './metric-selector'; -import { setGraphView, setTableView, setResourceView } from '../actions/app-actions'; +import { setResourceView } from '../actions/request-actions'; +import { setGraphView, setTableView } from '../actions/app-actions'; import { availableMetricsSelector } from '../selectors/node-metric'; import { isResourceViewModeSelector, diff --git a/client/app/scripts/router.js b/client/app/scripts/router.js index f1fc9571f..2b20190cc 100644 --- a/client/app/scripts/router.js +++ b/client/app/scripts/router.js @@ -2,7 +2,7 @@ import page from 'page'; import stableStringify from 'json-stable-stringify'; import { each } from 'lodash'; -import { route } from './actions/app-actions'; +import { route } from './actions/request-actions'; import { storageGet, storageSet } from './utils/storage-utils'; import { decodeURL, encodeURL, isStoreViewStateEnabled, STORAGE_STATE_KEY diff --git a/client/app/scripts/utils/web-api-utils.js b/client/app/scripts/utils/web-api-utils.js index b37bac8cb..7a2b57634 100644 --- a/client/app/scripts/utils/web-api-utils.js +++ b/client/app/scripts/utils/web-api-utils.js @@ -4,24 +4,18 @@ import { defaults } from 'lodash'; import { Map as makeMap, List } from 'immutable'; import { - closeWebsocket, openWebsocket, receiveError, - receiveApiDetails, receiveNodesDelta, receiveNodeDetails, - receiveControlPipeStatus, receiveTopologies, receiveNotFound, - receiveNodesForTopology, receiveNodes, + receiveError, + receiveNodeDetails, + receiveNotFound, receiveNodesForTopology, receiveNodes, } from '../actions/app-actions'; import { getCurrentTopologyUrl } from './topology-utils'; import { layersTopologyIdsSelector } from '../selectors/resource-view/layout'; import { activeTopologyOptionsSelector } from '../selectors/topology'; -import { isPausedSelector } from '../selectors/time-travel'; - -import { API_REFRESH_INTERVAL, TOPOLOGY_REFRESH_INTERVAL } from '../constants/timer'; const log = debug('scope:web-api-utils'); -const reconnectTimerInterval = 5000; const updateFrequency = '5s'; -const FIRST_RENDER_TOO_LONG_THRESHOLD = 100; // ms const csrfToken = (() => { // Check for token at window level or parent level (for iframe); /* eslint-disable no-underscore-dangle */ @@ -37,15 +31,6 @@ const csrfToken = (() => { return token; })(); -let socket; -let reconnectTimer = 0; -let topologyTimer = 0; -let apiDetailsTimer = 0; -let currentUrl = null; -let createWebsocketAt = null; -let firstMessageOnWebsocketAt = null; -let continuePolling = true; - export function buildUrlQuery(params = makeMap(), state = null) { // Attach the time travel timestamp to every request to the backend. if (state) { @@ -103,7 +88,7 @@ export function getReportUrl(timestamp) { return `${getApiPath()}/api/report?${buildUrlQuery(makeMap({ timestamp }))}`; } -function topologiesUrl(state) { +export function topologiesUrl(state) { const activeTopologyOptions = activeTopologyOptionsSelector(state); const optionsQuery = buildUrlQuery(activeTopologyOptions, state); return `${getApiPath()}/api/topology?${optionsQuery}`; @@ -114,68 +99,12 @@ export function getWebsocketUrl(host = window.location.host, pathname = window.l return `${wsProto}://${host}${getApiPath(pathname)}`; } -function buildWebsocketUrl(topologyUrl, topologyOptions = makeMap(), state) { +export function buildWebsocketUrl(topologyUrl, topologyOptions = makeMap(), state) { topologyOptions = topologyOptions.set('t', updateFrequency); const optionsQuery = buildUrlQuery(topologyOptions, state); return `${getWebsocketUrl()}${topologyUrl}/ws?${optionsQuery}`; } -function createWebsocket(websocketUrl, getState, dispatch) { - if (socket) { - socket.onclose = null; - socket.onerror = null; - socket.close(); - // onclose() is not called, but that's fine since we're opening a new one - // right away - } - - // profiling - createWebsocketAt = new Date(); - firstMessageOnWebsocketAt = null; - - socket = new WebSocket(websocketUrl); - - socket.onopen = () => { - log(`Opening websocket to ${websocketUrl}`); - dispatch(openWebsocket()); - }; - - socket.onclose = () => { - clearTimeout(reconnectTimer); - log(`Closing websocket to ${websocketUrl}`, socket.readyState); - socket = null; - dispatch(closeWebsocket()); - - if (continuePolling && !isPausedSelector(getState())) { - reconnectTimer = setTimeout(() => { - createWebsocket(websocketUrl, getState, dispatch); - }, reconnectTimerInterval); - } - }; - - socket.onerror = () => { - log(`Error in websocket to ${websocketUrl}`); - dispatch(receiveError(websocketUrl)); - }; - - socket.onmessage = (event) => { - const msg = JSON.parse(event.data); - dispatch(receiveNodesDelta(msg)); - - // profiling (receiveNodesDelta triggers synchronous render) - if (!firstMessageOnWebsocketAt) { - firstMessageOnWebsocketAt = new Date(); - const timeToFirstMessage = firstMessageOnWebsocketAt - createWebsocketAt; - if (timeToFirstMessage > FIRST_RENDER_TOO_LONG_THRESHOLD) { - log( - 'Time (ms) to first nodes render after websocket was created', - firstMessageOnWebsocketAt - createWebsocketAt - ); - } - } - }; -} - /** * XHR wrapper. Applies a CSRF token (if it exists) and content-type to all requests. * Any opts that get passed in will override the defaults. @@ -210,7 +139,7 @@ function getNodesForTopologies(state, dispatch, topologyIds, topologyOptions = m ); } -function getNodesOnce(getState, dispatch) { +export function getNodesOnce(getState, dispatch) { const state = getState(); const topologyUrl = getCurrentTopologyUrl(state); const topologyOptions = activeTopologyOptionsSelector(state); @@ -246,63 +175,6 @@ export function getResourceViewNodesSnapshot(state, dispatch) { getNodesForTopologies(state, dispatch, topologyIds); } -function pollTopologies(getState, dispatch, initialPoll = false) { - // Used to resume polling when navigating between pages in Weave Cloud. - continuePolling = initialPoll === true ? true : continuePolling; - clearTimeout(topologyTimer); - // NOTE: getState is called every time to make sure the up-to-date state is used. - const url = topologiesUrl(getState()); - doRequest({ - error: (req) => { - log(`Error in topology request: ${req.responseText}`); - dispatch(receiveError(url)); - // Only retry in stand-alone mode - if (continuePolling && !isPausedSelector(getState())) { - topologyTimer = setTimeout(() => { - pollTopologies(getState, dispatch); - }, TOPOLOGY_REFRESH_INTERVAL); - } - }, - success: (res) => { - if (continuePolling && !isPausedSelector(getState())) { - dispatch(receiveTopologies(res)); - topologyTimer = setTimeout(() => { - pollTopologies(getState, dispatch); - }, TOPOLOGY_REFRESH_INTERVAL); - } - }, - url - }); -} - -function getTopologiesOnce(getState, dispatch) { - const url = topologiesUrl(getState()); - doRequest({ - error: (req) => { - log(`Error in topology request: ${req.responseText}`); - dispatch(receiveError(url)); - }, - success: (res) => { - dispatch(receiveTopologies(res)); - }, - url - }); -} - -function updateWebsocketChannel(getState, dispatch, forceRequest) { - const topologyUrl = getCurrentTopologyUrl(getState()); - const topologyOptions = activeTopologyOptionsSelector(getState()); - const websocketUrl = buildWebsocketUrl(topologyUrl, topologyOptions, getState()); - // Only recreate websocket if url changed or if forced (weave cloud instance reload); - const isNewUrl = websocketUrl !== currentUrl; - // `topologyUrl` can be undefined initially, so only create a socket if it is truthy - // and no socket exists, or if we get a new url. - if (topologyUrl && (!socket || isNewUrl || forceRequest)) { - createWebsocket(websocketUrl, getState, dispatch); - currentUrl = websocketUrl; - } -} - export function getNodeDetails(getState, dispatch) { const state = getState(); const nodeMap = state.get('nodeDetails'); @@ -349,48 +221,6 @@ export function getNodeDetails(getState, dispatch) { } } -export function getTopologies(getState, dispatch, forceRequest) { - if (isPausedSelector(getState())) { - getTopologiesOnce(getState, dispatch); - } else { - pollTopologies(getState, dispatch, forceRequest); - } -} - -export function getNodes(getState, dispatch, forceRequest = false) { - if (isPausedSelector(getState())) { - getNodesOnce(getState, dispatch); - } else { - updateWebsocketChannel(getState, dispatch, forceRequest); - } - getNodeDetails(getState, dispatch); -} - -export function getApiDetails(dispatch) { - clearTimeout(apiDetailsTimer); - const url = `${getApiPath()}/api`; - doRequest({ - error: (req) => { - log(`Error in api details request: ${req.responseText}`); - receiveError(url); - if (continuePolling) { - apiDetailsTimer = setTimeout(() => { - getApiDetails(dispatch); - }, API_REFRESH_INTERVAL / 2); - } - }, - success: (res) => { - dispatch(receiveApiDetails(res)); - if (continuePolling) { - apiDetailsTimer = setTimeout(() => { - getApiDetails(dispatch); - }, API_REFRESH_INTERVAL); - } - }, - url - }); -} - export function doResizeTty(pipeId, control, cols, rows) { const url = `${getApiPath()}/api/control/${encodeURIComponent(control.probeId)}/` + `${encodeURIComponent(control.nodeId)}/${control.id}`; @@ -420,44 +250,3 @@ export function deletePipe(pipeId, dispatch) { url }); } - - -export function getPipeStatus(pipeId, dispatch) { - const url = `${getApiPath()}/api/pipe/${encodeURIComponent(pipeId)}/check`; - doRequest({ - complete: (res) => { - const status = { - 204: 'PIPE_ALIVE', - 404: 'PIPE_DELETED' - }[res.status]; - - if (!status) { - log('Unexpected pipe status:', res.status); - return; - } - - dispatch(receiveControlPipeStatus(pipeId, status)); - }, - method: 'GET', - url - }); -} - -export function stopPolling() { - clearTimeout(apiDetailsTimer); - clearTimeout(topologyTimer); - continuePolling = false; -} - -export function teardownWebsockets() { - clearTimeout(reconnectTimer); - if (socket) { - socket.onerror = null; - socket.onclose = null; - socket.onmessage = null; - socket.onopen = null; - socket.close(); - socket = null; - currentUrl = null; - } -}
- {this.props.renderIdCell(Object.assign(node, {nodeId, topologyId}))} + {this.props.renderIdCell(Object.assign(node, { nodeId, topologyId }))}