diff --git a/console/package-lock.json b/console/package-lock.json index 0f2f97ae59..4b33c089f6 100644 --- a/console/package-lock.json +++ b/console/package-lock.json @@ -4,16 +4,26 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@angular-devkit/build-angular": { - "version": "0.1102.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1102.0.tgz", - "integrity": "sha512-9Yl6qBOR1o0ThyLhrWJ6Rhr3qLRe+RP3sbfUt4QA+8wsIXN7WakEXJALlq7TDeG66OaWyyjbtC2q3EPdNeBC/g==", + "@angular-devkit/architect": { + "version": "0.1102.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1102.1.tgz", + "integrity": "sha512-s7CxUANGssLYL0KNdNUjXKjtzPjxnAMW9s7H/wzYuFqXVq/DbHvIMAEQW4x7XD5sD8zTqcVR8QAL6ZVSYHppVw==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1102.0", - "@angular-devkit/build-optimizer": "0.1102.0", - "@angular-devkit/build-webpack": "0.1102.0", - "@angular-devkit/core": "11.2.0", + "@angular-devkit/core": "11.2.1", + "rxjs": "6.6.3" + } + }, + "@angular-devkit/build-angular": { + "version": "0.1102.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1102.1.tgz", + "integrity": "sha512-1kCLKGVtq20UEPWHzaAF/HDPE4wTzaqIvV29+Bdv8t7QfBtuabZfcpB/9mY14Yh7Z1rHBlKz/OVGff09NUK0Ww==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1102.1", + "@angular-devkit/build-optimizer": "0.1102.1", + "@angular-devkit/build-webpack": "0.1102.1", + "@angular-devkit/core": "11.2.1", "@babel/core": "7.12.10", "@babel/generator": "7.12.11", "@babel/plugin-transform-async-to-generator": "7.12.1", @@ -22,7 +32,7 @@ "@babel/runtime": "7.12.5", "@babel/template": "7.12.7", "@jsdevtools/coverage-istanbul-loader": "3.0.5", - "@ngtools/webpack": "11.2.0", + "@ngtools/webpack": "11.2.1", "ansi-colors": "4.1.1", "autoprefixer": "10.2.4", "babel-loader": "8.2.2", @@ -32,7 +42,7 @@ "circular-dependency-plugin": "5.2.2", "copy-webpack-plugin": "6.3.2", "core-js": "3.8.3", - "critters": "0.0.6", + "critters": "0.0.7", "css-loader": "5.0.1", "cssnano": "4.1.10", "file-loader": "6.2.0", @@ -84,29 +94,6 @@ "worker-plugin": "5.0.0" }, "dependencies": { - "@angular-devkit/architect": { - "version": "0.1102.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1102.0.tgz", - "integrity": "sha512-d9Da6SiTiDb5N1avxWLcPHSyWCq3G62TlROXxr32WkcQRko8wtgW5VOzgSkdmY2p6UTSME89naUojfzgu2Wh6g==", - "dev": true, - "requires": { - "@angular-devkit/core": "11.2.0", - "rxjs": "6.6.3" - } - }, - "@angular-devkit/core": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.0.tgz", - "integrity": "sha512-qqYEH8m/bwpngoLDMFuth8ykvoHxQ3aHHnAWfRXz9NXydwSfathG0VSYCctB126sK39JKIn+xq16CQAExxNu+Q==", - "dev": true, - "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" - } - }, "@babel/code-frame": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", @@ -206,12 +193,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-module-imports": { @@ -224,9 +211,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz", - "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.17.tgz", + "integrity": "sha512-sFL+p6zOCQMm9vilo06M4VHuTxUAwa6IxgL56Tq1DVtA0ziAGTH1ThmJq7xwPqdQlgAbKX3fb0oZNbtRIyA5KQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.12.13", @@ -235,8 +222,8 @@ "@babel/helper-split-export-declaration": "^7.12.13", "@babel/helper-validator-identifier": "^7.12.11", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/traverse": "^7.12.17", + "@babel/types": "^7.12.17", "lodash": "^4.17.19" }, "dependencies": { @@ -299,14 +286,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.13.tgz", - "integrity": "sha512-oohVzLRZ3GQEk4Cjhfs9YkJA4TdIDTObdBEZGrd6F/T0GPSnuV6l22eMcxlvcvzVIPH3VTtxbseudM1zIE+rPQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.17.tgz", + "integrity": "sha512-tEpjqSBGt/SFEsFikKds1sLNChKKGGR17flIgQKXH4fG6m9gTgl3gnOC1giHNyaBCSKuTfxaSzHi7UnvqiVKxg==", "dev": true, "requires": { "@babel/template": "^7.12.13", - "@babel/traverse": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/traverse": "^7.12.17", + "@babel/types": "^7.12.17" }, "dependencies": { "@babel/template": { @@ -334,9 +321,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -351,29 +338,29 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" }, "dependencies": { "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -387,9 +374,9 @@ } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -406,33 +393,6 @@ "debug": "4" } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, "autoprefixer": { "version": "10.2.4", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.4.tgz", @@ -461,28 +421,13 @@ } }, "caniuse-lite": { - "version": "1.0.30001187", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001187.tgz", - "integrity": "sha512-w7/EP1JRZ9552CyrThUnay2RkZ1DXxKe/Q2swTC4+LElLh9RRYrL1Z+27LlakB8kzY0fSmHw9mc7XYDUKAKWMA==", + "version": "1.0.30001190", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001190.tgz", + "integrity": "sha512-62KVw474IK8E+bACBYhRS0/L6o/1oeAVkpF2WetjV58S5vkzNh0/Rz3lD8D4YCbOTqi0/aD4X3LtoP7V5xnuAg==", "dev": true } } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -493,9 +438,9 @@ } }, "electron-to-chromium": { - "version": "1.3.664", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.664.tgz", - "integrity": "sha512-yb8LrTQXQnh9yhnaIHLk6CYugF/An50T20+X0h++hjjhVfgSp1DGoMSYycF8/aD5eiqS4QwaNhiduFvK8rifRg==", + "version": "1.3.671", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.671.tgz", + "integrity": "sha512-RTD97QkdrJKaKwRv9h/wGAaoR2lGxNXEcBXS31vjitgTPwTWAbLdS7cEsBK68eEQy7p6YyT8D5BxBEYHu2SuwQ==", "dev": true }, "escalade": { @@ -504,12 +449,6 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "https-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", @@ -526,44 +465,6 @@ "integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==", "dev": true }, - "open": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.0.tgz", - "integrity": "sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA==", - "dev": true, - "requires": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - } - }, - "ora": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", - "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "log-symbols": "^4.0.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } - } - }, "postcss": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.4.tgz", @@ -606,31 +507,13 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, "@angular-devkit/build-optimizer": { - "version": "0.1102.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.0.tgz", - "integrity": "sha512-0Xb7xR0iUrbo/BnKJPTsy5IuodfFUWbvXUu9qeKc+oHzwxObX4Y32X0yyRpIJc5UK7Ce43HkopRQ/tHdoJp2fQ==", + "version": "0.1102.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1102.1.tgz", + "integrity": "sha512-/VXu76P5LWKxT7+x3P/xsRr1P22y+7erpKX1V6Y07b6KwMoButH/hch8cBPsLPc9QWoVxSuyBzouXQPbXlT/LA==", "dev": true, "requires": { "loader-utils": "2.0.0", @@ -661,39 +544,29 @@ } }, "@angular-devkit/build-webpack": { - "version": "0.1102.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1102.0.tgz", - "integrity": "sha512-bfd6WlxcbWJ01HNNcFt4sBBaY+Bz2J/zFA6BSORvC5LpqawYCYeUbDJTY9Wb7gtp+aPEiNHI0HeUvoNkubsYfg==", + "version": "0.1102.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1102.1.tgz", + "integrity": "sha512-KaC1z0zL7gBjEfxVKMJQ0fCIDwn1wy3fYm/0V9MNEyeDyV8JfxWVy4RgkIyn8+aHBdYdZYF2mFrxpB1/IahJMw==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1102.0", - "@angular-devkit/core": "11.2.0", + "@angular-devkit/architect": "0.1102.1", + "@angular-devkit/core": "11.2.1", "rxjs": "6.6.3" + } + }, + "@angular-devkit/core": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.1.tgz", + "integrity": "sha512-CPFQn+NNC4x28X/STwmwmWge127iY9dsKuXeIV8OCSTOQiY4odOTYigP19AglXyK4e9DG/0JKxej/3CeUYx6Tg==", + "dev": true, + "requires": { + "ajv": "6.12.6", + "fast-json-stable-stringify": "2.1.0", + "magic-string": "0.25.7", + "rxjs": "6.6.3", + "source-map": "0.7.3" }, "dependencies": { - "@angular-devkit/architect": { - "version": "0.1102.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1102.0.tgz", - "integrity": "sha512-d9Da6SiTiDb5N1avxWLcPHSyWCq3G62TlROXxr32WkcQRko8wtgW5VOzgSkdmY2p6UTSME89naUojfzgu2Wh6g==", - "dev": true, - "requires": { - "@angular-devkit/core": "11.2.0", - "rxjs": "6.6.3" - } - }, - "@angular-devkit/core": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.0.tgz", - "integrity": "sha512-qqYEH8m/bwpngoLDMFuth8ykvoHxQ3aHHnAWfRXz9NXydwSfathG0VSYCctB126sK39JKIn+xq16CQAExxNu+Q==", - "dev": true, - "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1405,9 +1278,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1434,9 +1307,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1447,13 +1320,13 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.16.tgz", - "integrity": "sha512-dBHNEEaZx7F3KoUYqagIhRIeqyyuI65xMndMZ3WwGwEBI609I4TleYQHcrS627vbKyNTXqShoN+fvYD9HuQxAg==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.17.tgz", + "integrity": "sha512-5EkibqLVYOuZ89BSg2lv+GG8feywLuvMXNYgf0Im4MssE0mFWPztSpJbildNnUgw0bLI2EsIN4MpSHC2iUJkQA==", "dev": true, "requires": { "@babel/compat-data": "^7.12.13", - "@babel/helper-validator-option": "^7.12.16", + "@babel/helper-validator-option": "^7.12.17", "browserslist": "^4.14.5", "semver": "^5.5.0" }, @@ -1472,15 +1345,15 @@ } }, "caniuse-lite": { - "version": "1.0.30001187", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001187.tgz", - "integrity": "sha512-w7/EP1JRZ9552CyrThUnay2RkZ1DXxKe/Q2swTC4+LElLh9RRYrL1Z+27LlakB8kzY0fSmHw9mc7XYDUKAKWMA==", + "version": "1.0.30001190", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001190.tgz", + "integrity": "sha512-62KVw474IK8E+bACBYhRS0/L6o/1oeAVkpF2WetjV58S5vkzNh0/Rz3lD8D4YCbOTqi0/aD4X3LtoP7V5xnuAg==", "dev": true }, "electron-to-chromium": { - "version": "1.3.664", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.664.tgz", - "integrity": "sha512-yb8LrTQXQnh9yhnaIHLk6CYugF/An50T20+X0h++hjjhVfgSp1DGoMSYycF8/aD5eiqS4QwaNhiduFvK8rifRg==", + "version": "1.3.671", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.671.tgz", + "integrity": "sha512-RTD97QkdrJKaKwRv9h/wGAaoR2lGxNXEcBXS31vjitgTPwTWAbLdS7cEsBK68eEQy7p6YyT8D5BxBEYHu2SuwQ==", "dev": true }, "escalade": { @@ -1498,13 +1371,13 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.16.tgz", - "integrity": "sha512-KbSEj8l9zYkMVHpQqM3wJNxS1d9h3U9vm/uE5tpjMbaj3lTp+0noe3KPsV5dSD9jxKnf9jO9Ip9FX5PKNZCKow==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.17.tgz", + "integrity": "sha512-I/nurmTxIxHV0M+rIpfQBF1oN342+yvl2kwZUrQuOClMamHF1w5tknfZubgNOLRoA73SzBFAdFcpb4M9HwOeWQ==", "dev": true, "requires": { "@babel/helper-function-name": "^7.12.13", - "@babel/helper-member-expression-to-functions": "^7.12.16", + "@babel/helper-member-expression-to-functions": "^7.12.17", "@babel/helper-optimise-call-expression": "^7.12.13", "@babel/helper-replace-supers": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13" @@ -1520,12 +1393,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -1551,12 +1424,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-optimise-call-expression": { @@ -1607,9 +1480,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -1624,26 +1497,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1669,9 +1542,9 @@ } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.16.tgz", - "integrity": "sha512-jAcQ1biDYZBdaAxB4yg46/XirgX7jBDiMHDbwYQOgtViLBXGxJpZQ24jutmBqAIB/q+AwB6j+NbBXjKxEY8vqg==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", + "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.12.13", @@ -1694,9 +1567,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1775,9 +1648,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1886,9 +1759,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1969,9 +1842,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -1997,9 +1870,9 @@ "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.16.tgz", - "integrity": "sha512-uCgsDBPUQDvzr11ePPo4TVEocxj8RXjUVSC/Y8N1YpVAI/XDdUwGJu78xmlGhTxj2ntaWM7n9LQdRtyhOzT2YQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", "dev": true }, "@babel/helper-wrap-function": { @@ -2024,12 +1897,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -2081,9 +1954,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -2098,26 +1971,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -2225,9 +2098,9 @@ } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.16.tgz", - "integrity": "sha512-yiDkYFapVxNOCcBfLnsb/qdsliroM+vc3LHiZwS4gh7pFjo5Xq3BDhYBNn3H3ao+hWPvqeeTdU+s+FIvokov+w==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.17.tgz", + "integrity": "sha512-ZNGoFZqrnuy9H2izB2jLlnNDAfVPlGl5NhFEiFe4D84ix9GQGygF+CWMGHKuE+bpyS/AOuDQCnkiRNqW2IzS1Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.12.13", @@ -2306,9 +2179,9 @@ } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.16.tgz", - "integrity": "sha512-O3ohPwOhkwji5Mckb7F/PJpJVJY3DpPsrt/F0Bk40+QMk9QpAIqeGusHWqu/mYqsM8oBa6TziL/2mbERWsUZjg==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.17.tgz", + "integrity": "sha512-TvxwI80pWftrGPKHNfkvX/HnoeSTR7gC4ezWnAL39PuktYUe6r8kEpOLTYnkBTsaoeazXm2jHJ22EQ81sdgfcA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.12.13", @@ -2480,9 +2353,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -2535,12 +2408,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -2566,12 +2439,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-optimise-call-expression": { @@ -2622,9 +2495,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -2639,26 +2512,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -2796,9 +2669,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -2813,9 +2686,9 @@ } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -2864,12 +2737,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -2895,12 +2768,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-module-imports": { @@ -2913,9 +2786,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz", - "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.17.tgz", + "integrity": "sha512-sFL+p6zOCQMm9vilo06M4VHuTxUAwa6IxgL56Tq1DVtA0ziAGTH1ThmJq7xwPqdQlgAbKX3fb0oZNbtRIyA5KQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.12.13", @@ -2924,8 +2797,8 @@ "@babel/helper-split-export-declaration": "^7.12.13", "@babel/helper-validator-identifier": "^7.12.11", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/traverse": "^7.12.17", + "@babel/types": "^7.12.17", "lodash": "^4.17.19" } }, @@ -2986,9 +2859,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -3003,26 +2876,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -3069,12 +2942,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -3100,12 +2973,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-module-imports": { @@ -3118,9 +2991,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz", - "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.17.tgz", + "integrity": "sha512-sFL+p6zOCQMm9vilo06M4VHuTxUAwa6IxgL56Tq1DVtA0ziAGTH1ThmJq7xwPqdQlgAbKX3fb0oZNbtRIyA5KQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.12.13", @@ -3129,8 +3002,8 @@ "@babel/helper-split-export-declaration": "^7.12.13", "@babel/helper-validator-identifier": "^7.12.11", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/traverse": "^7.12.17", + "@babel/types": "^7.12.17", "lodash": "^4.17.19" } }, @@ -3191,9 +3064,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -3208,26 +3081,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -3275,12 +3148,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -3306,12 +3179,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-module-imports": { @@ -3324,9 +3197,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz", - "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.17.tgz", + "integrity": "sha512-sFL+p6zOCQMm9vilo06M4VHuTxUAwa6IxgL56Tq1DVtA0ziAGTH1ThmJq7xwPqdQlgAbKX3fb0oZNbtRIyA5KQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.12.13", @@ -3335,8 +3208,8 @@ "@babel/helper-split-export-declaration": "^7.12.13", "@babel/helper-validator-identifier": "^7.12.11", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/traverse": "^7.12.17", + "@babel/types": "^7.12.17", "lodash": "^4.17.19" } }, @@ -3397,9 +3270,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -3414,26 +3287,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -3478,12 +3351,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -3509,12 +3382,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-module-imports": { @@ -3527,9 +3400,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.13.tgz", - "integrity": "sha512-acKF7EjqOR67ASIlDTupwkKM1eUisNAjaSduo5Cz+793ikfnpe7p4Q7B7EWU2PCoSTPWsQkR7hRUWEIZPiVLGA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.17.tgz", + "integrity": "sha512-sFL+p6zOCQMm9vilo06M4VHuTxUAwa6IxgL56Tq1DVtA0ziAGTH1ThmJq7xwPqdQlgAbKX3fb0oZNbtRIyA5KQ==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.12.13", @@ -3538,8 +3411,8 @@ "@babel/helper-split-export-declaration": "^7.12.13", "@babel/helper-validator-identifier": "^7.12.11", "@babel/template": "^7.12.13", - "@babel/traverse": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/traverse": "^7.12.17", + "@babel/types": "^7.12.17", "lodash": "^4.17.19" } }, @@ -3600,9 +3473,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -3617,26 +3490,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -3699,12 +3572,12 @@ } }, "@babel/generator": { - "version": "7.12.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.15.tgz", - "integrity": "sha512-6F2xHxBiFXWNSGb7vyCUTBF8RCLY66rS0zEPcP8t/nQyXjha5EuK4z7H5o7fWG8B4M7y6mqVWq1J+1PuwRhecQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.17.tgz", + "integrity": "sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==", "dev": true, "requires": { - "@babel/types": "^7.12.13", + "@babel/types": "^7.12.17", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -3730,12 +3603,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.16.tgz", - "integrity": "sha512-zYoZC1uvebBFmj1wFAlXwt35JLEgecefATtKp20xalwEK8vHAixLBXTGxNrVGEmTT+gzOThUgr8UEdgtalc1BQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.17.tgz", + "integrity": "sha512-Bzv4p3ODgS/qpBE0DiJ9qf5WxSmrQ8gVTe8ClMfwwsY2x/rhykxxy3bXzG7AGTnPB2ij37zGJ/Q/6FruxHxsxg==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.12.17" } }, "@babel/helper-optimise-call-expression": { @@ -3786,9 +3659,9 @@ } }, "@babel/parser": { - "version": "7.12.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.16.tgz", - "integrity": "sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", + "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", "dev": true }, "@babel/template": { @@ -3803,26 +3676,26 @@ } }, "@babel/traverse": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz", - "integrity": "sha512-3Zb4w7eE/OslI0fTp8c7b286/cQps3+vdLW3UcwC8VSJC6GbKn55aeVVu2QJNuCDoeKyptLOFrPq8WqZZBodyA==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.17.tgz", + "integrity": "sha512-LGkTqDqdiwC6Q7fWSwQoas/oyiEYw6Hqjve5KOSykXkmFJFqzvGMb9niaUEag3Rlve492Mkye3gLw9FTv94fdQ==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.12.13", + "@babel/generator": "^7.12.17", "@babel/helper-function-name": "^7.12.13", "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13", + "@babel/parser": "^7.12.17", + "@babel/types": "^7.12.17", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" } }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -3910,9 +3783,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -4077,9 +3950,9 @@ "dev": true }, "@babel/types": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz", - "integrity": "sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", + "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.12.11", @@ -4218,47 +4091,14 @@ } }, "@ngtools/webpack": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.2.0.tgz", - "integrity": "sha512-2KYaA/fIw863jydXDolWp4kUNLODVIKs2834vW+oztocnYFe/z4dTz6rArKFUCixMCu12ieXrjAetzGA564bsg==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-11.2.1.tgz", + "integrity": "sha512-Waz+ktPO9DkS++xt/JNLubkzz3iSgbwxGkeu1rymaD95zpMw9EPxe0FJ2dmMWr2VoSHTbap/W9qczsvfQxBFTg==", "dev": true, "requires": { - "@angular-devkit/core": "11.2.0", + "@angular-devkit/core": "11.2.1", "enhanced-resolve": "5.7.0", "webpack-sources": "2.2.0" - }, - "dependencies": { - "@angular-devkit/core": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.0.tgz", - "integrity": "sha512-qqYEH8m/bwpngoLDMFuth8ykvoHxQ3aHHnAWfRXz9NXydwSfathG0VSYCctB126sK39JKIn+xq16CQAExxNu+Q==", - "dev": true, - "requires": { - "ajv": "6.12.6", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.3", - "source-map": "0.7.3" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } } }, "@ngx-translate/core": { @@ -6717,12 +6557,12 @@ "dev": true }, "core-js-compat": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.3.tgz", - "integrity": "sha512-1sCb0wBXnBIL16pfFG1Gkvei6UzvKyTNYpiC41yrdjEv0UoJoq9E/abTMzyYJ6JpTkAj15dLjbqifIzEBDVvog==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.0.tgz", + "integrity": "sha512-YK6fwFjCOKWwGnjFUR3c544YsnA/7DoLL0ysncuOJ4pwbriAtOpvM2bygdlcXbvQCQZ7bBU9CL4t7tGl7ETRpQ==", "dev": true, "requires": { - "browserslist": "^4.16.1", + "browserslist": "^4.16.3", "semver": "7.0.0" }, "dependencies": { @@ -6740,15 +6580,15 @@ } }, "caniuse-lite": { - "version": "1.0.30001187", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001187.tgz", - "integrity": "sha512-w7/EP1JRZ9552CyrThUnay2RkZ1DXxKe/Q2swTC4+LElLh9RRYrL1Z+27LlakB8kzY0fSmHw9mc7XYDUKAKWMA==", + "version": "1.0.30001190", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001190.tgz", + "integrity": "sha512-62KVw474IK8E+bACBYhRS0/L6o/1oeAVkpF2WetjV58S5vkzNh0/Rz3lD8D4YCbOTqi0/aD4X3LtoP7V5xnuAg==", "dev": true }, "electron-to-chromium": { - "version": "1.3.664", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.664.tgz", - "integrity": "sha512-yb8LrTQXQnh9yhnaIHLk6CYugF/An50T20+X0h++hjjhVfgSp1DGoMSYycF8/aD5eiqS4QwaNhiduFvK8rifRg==", + "version": "1.3.671", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.671.tgz", + "integrity": "sha512-RTD97QkdrJKaKwRv9h/wGAaoR2lGxNXEcBXS31vjitgTPwTWAbLdS7cEsBK68eEQy7p6YyT8D5BxBEYHu2SuwQ==", "dev": true }, "escalade": { @@ -6868,9 +6708,9 @@ "dev": true }, "critters": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.6.tgz", - "integrity": "sha512-NUB3Om7tkf+XWi9+2kJ2A3l4/tHORDI1UT+nHxUqay2B/tJvMpiXcklDDLBH3fPn9Pe23uu0we/08Ukjy4cLCQ==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.7.tgz", + "integrity": "sha512-qUF2SaAWFYjNPdCcPpu68p2DnHiosia84yx5mPTlUMQjkjChR+n6sO1/I7yn2U2qNDgSPTd2SoaTIDQcUL+EwQ==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -8294,9 +8134,9 @@ }, "dependencies": { "type": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.2.0.tgz", - "integrity": "sha512-M/u37b4oSGlusaU8ZB96BfFPWQ8MbsZYXB+kXGMiDj6IKinkcNaQvmirBuWj8mAXqP6LYn1rQvbTYum3yPhaOA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.3.0.tgz", + "integrity": "sha512-rgPIqOdfK/4J9FhiVrZ3cveAjRRo5rsQBAIhnylX874y1DX/kEKSVdLsnuHB6l1KTjHyU01VjiMBHgU2adejyg==", "dev": true } } @@ -10164,9 +10004,9 @@ "dev": true }, "is-what": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.12.0.tgz", - "integrity": "sha512-2ilQz5/f/o9V7WRWJQmpFYNmQFZ9iM+OXRonZKcYgTkCzjb949Vi4h282PD1UfmgHk666rcWonbRJ++KI41VGw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true }, "is-windows": { @@ -10837,18 +10677,6 @@ "semver": "^5.6.0" } }, - "needle": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", - "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -12341,12 +12169,12 @@ "dev": true }, "object-is": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", - "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -12378,14 +12206,14 @@ } }, "object.getownpropertydescriptors": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", - "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" + "es-abstract": "^1.18.0-next.2" } }, "object.pick": { @@ -12447,6 +12275,16 @@ "mimic-fn": "^2.1.0" } }, + "open": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.0.tgz", + "integrity": "sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -12469,6 +12307,88 @@ "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz", "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4=" }, + "ora": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "log-symbols": "^4.0.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -13611,9 +13531,9 @@ "dev": true }, "pretty-bytes": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.5.0.tgz", - "integrity": "sha512-p+T744ZyjjiaFlMUZZv6YPC5JrkNj8maRmPaQCWFJFplUAzpIUTRaTcS+7wmZtUoFXHtESJb23ISliaWyz3SHA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true }, "process": { @@ -17458,9 +17378,9 @@ } }, "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", - "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", "dev": true, "requires": { "querystringify": "^2.1.1", @@ -18270,9 +18190,9 @@ }, "dependencies": { "mime": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.0.tgz", - "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", "dev": true } } diff --git a/console/package.json b/console/package.json index 31e162618b..63b98698f6 100644 --- a/console/package.json +++ b/console/package.json @@ -45,7 +45,7 @@ }, "devDependencies": { "@angular/cli": "~11.2.0", - "@angular-devkit/build-angular": "~0.1102.0", + "@angular-devkit/build-angular": "~0.1102.1", "@angular/compiler-cli": "~11.0.0", "@types/jasmine": "~3.6.3", "@angular/language-service": "~11.2.0", diff --git a/console/src/app/app.component.ts b/console/src/app/app.component.ts index 4de87c5279..664dd36d12 100644 --- a/console/src/app/app.component.ts +++ b/console/src/app/app.component.ts @@ -143,6 +143,37 @@ export class AppComponent implements OnDestroy { 'mdi_pin', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/pin.svg'), ); + + this.matIconRegistry.addSvgIcon( + 'mdi_format-letter-case-lower', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/format-letter-case-lower.svg'), + ); + + this.matIconRegistry.addSvgIcon( + 'mdi_format-letter-case-upper', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/format-letter-case-upper.svg'), + ); + + this.matIconRegistry.addSvgIcon( + 'mdi_counter', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/counter.svg'), + ); + + this.matIconRegistry.addSvgIcon( + 'mdi_symbol', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/symbol.svg'), + ); + + this.matIconRegistry.addSvgIcon( + 'mdi_numeric', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/numeric.svg'), + ); + + this.matIconRegistry.addSvgIcon( + 'mdi_api', + this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/api.svg'), + ); + this.getProjectCount(); this.orgSub = this.authService.activeOrgChanged.subscribe(org => { diff --git a/console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.html b/console/src/app/modules/add-key-dialog/add-key-dialog.component.html similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.html rename to console/src/app/modules/add-key-dialog/add-key-dialog.component.html diff --git a/console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.scss b/console/src/app/modules/add-key-dialog/add-key-dialog.component.scss similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.scss rename to console/src/app/modules/add-key-dialog/add-key-dialog.component.scss diff --git a/console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.spec.ts b/console/src/app/modules/add-key-dialog/add-key-dialog.component.spec.ts similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.spec.ts rename to console/src/app/modules/add-key-dialog/add-key-dialog.component.spec.ts diff --git a/console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.ts b/console/src/app/modules/add-key-dialog/add-key-dialog.component.ts similarity index 59% rename from console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.ts rename to console/src/app/modules/add-key-dialog/add-key-dialog.component.ts index 83e48426c9..f02ada00f2 100644 --- a/console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.component.ts +++ b/console/src/app/modules/add-key-dialog/add-key-dialog.component.ts @@ -1,7 +1,12 @@ import { Component, Inject } from '@angular/core'; import { FormControl } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { MachineKeyType } from 'src/app/proto/generated/management_pb'; +import { AuthNKeyType, MachineKeyType } from 'src/app/proto/generated/management_pb'; + +export enum AddKeyDialogType { + MACHINE = "MACHINE", + AUTHNKEY = "AUTHNKEY", +} @Component({ selector: 'app-add-key-dialog', @@ -10,16 +15,21 @@ import { MachineKeyType } from 'src/app/proto/generated/management_pb'; }) export class AddKeyDialogComponent { public startDate: Date = new Date(); - types: MachineKeyType[] = [ - MachineKeyType.MACHINEKEY_JSON, - ]; - public type: MachineKeyType = MachineKeyType.MACHINEKEY_JSON; + types: MachineKeyType[] | AuthNKeyType[] = []; + public type!: MachineKeyType | AuthNKeyType; public dateControl: FormControl = new FormControl('', []); constructor( public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, ) { + if (data.type = AddKeyDialogType.MACHINE) { + this.types = [MachineKeyType.MACHINEKEY_JSON]; + this.type = MachineKeyType.MACHINEKEY_JSON; + } else if (data.type = AddKeyDialogType.AUTHNKEY) { + this.types = [AuthNKeyType.AUTHNKEY_JSON]; + this.type = AuthNKeyType.AUTHNKEY_JSON; + } const today = new Date(); this.startDate.setDate(today.getDate() + 1); } diff --git a/console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.module.ts b/console/src/app/modules/add-key-dialog/add-key-dialog.module.ts similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/add-key-dialog/add-key-dialog.module.ts rename to console/src/app/modules/add-key-dialog/add-key-dialog.module.ts diff --git a/console/src/app/modules/app-card/app-card.component.html b/console/src/app/modules/app-card/app-card.component.html index 9730ff5111..9023bc3143 100644 --- a/console/src/app/modules/app-card/app-card.component.html +++ b/console/src/app/modules/app-card/app-card.component.html @@ -1,5 +1,5 @@
+ 'native': type == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE, 'api': isApiApp}">
\ No newline at end of file diff --git a/console/src/app/modules/app-card/app-card.component.scss b/console/src/app/modules/app-card/app-card.component.scss index dbbbb370f6..437710b84b 100644 --- a/console/src/app/modules/app-card/app-card.component.scss +++ b/console/src/app/modules/app-card/app-card.component.scss @@ -45,5 +45,11 @@ color: white; border: none; } + + &.api { + background-color: #333; + color: white; + border: none; + } } } diff --git a/console/src/app/modules/app-card/app-card.component.ts b/console/src/app/modules/app-card/app-card.component.ts index 4d53c84d3d..98e88c2084 100644 --- a/console/src/app/modules/app-card/app-card.component.ts +++ b/console/src/app/modules/app-card/app-card.component.ts @@ -9,6 +9,6 @@ import { OIDCApplicationType } from 'src/app/proto/generated/management_pb'; export class AppCardComponent { @Input() public outline: boolean = false; @Input() public type!: OIDCApplicationType; - + @Input() public isApiApp: boolean = false; public OIDCApplicationType: any = OIDCApplicationType; } diff --git a/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.html b/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.html index 41daf57cb3..dca80f54df 100644 --- a/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.html +++ b/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.html @@ -17,17 +17,21 @@

{{method.descI18nKey | translate}}

-
- {{'APP.OIDC.RESPONSE' | translate}} - {{('APP.OIDC.RESPONSE'+method.responseType.toString()) | translate}} +
+ {{'APP.OIDC.RESPONSETYPE' | translate}} + {{('APP.OIDC.RESPONSE.'+method.responseType.toString()) | translate}}
-
+
{{'APP.GRANT' | translate}} - {{('APP.OIDC.GRANT'+method.grantType.toString()) | translate}} + {{('APP.OIDC.GRANT.'+method.grantType.toString()) | translate}}
-
- {{'APP.OIDC.AUTHMETHOD' | translate}} - {{('APP.OIDC.AUTHMETHOD'+method.authMethod.toString()) | translate}} +
+ {{'APP.AUTHMETHOD' | translate}} + {{('APP.OIDC.AUTHMETHOD.'+method.authMethod.toString()) | translate}} +
+
+ {{'APP.AUTHMETHOD' | translate}} + {{('APP.API.AUTHMETHOD.'+method.apiAuthMethod.toString()) | translate}}
diff --git a/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.ts b/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.ts index 0561837493..cfc36c1704 100644 --- a/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.ts +++ b/console/src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { OIDCAuthMethodType, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb'; +import { APIAuthMethodType, OIDCAuthMethodType, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb'; export interface RadioItemAuthType { key: string; @@ -11,6 +11,7 @@ export interface RadioItemAuthType { responseType?: OIDCResponseType; grantType?: OIDCGrantType; authMethod?: OIDCAuthMethodType; + apiAuthMethod?: | APIAuthMethodType; recommended?: boolean; notRecommended?: boolean; } @@ -24,6 +25,7 @@ export class AppAuthMethodRadioComponent { @Input() current: string = ''; @Input() selected: string = ''; @Input() authMethods!: RadioItemAuthType[]; + @Input() isOIDC: boolean = false; @Output() selectedMethod: EventEmitter = new EventEmitter(); public emitChange(): void { diff --git a/console/src/app/modules/app-radio/app-type-radio/app-type-radio.component.html b/console/src/app/modules/app-radio/app-type-radio/app-type-radio.component.html index 0955190c94..5999665d07 100644 --- a/console/src/app/modules/app-radio/app-type-radio/app-type-radio.component.html +++ b/console/src/app/modules/app-radio/app-type-radio/app-type-radio.component.html @@ -1,8 +1,7 @@
- -
-
  • - - {{event.changeDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}} - - {{event.editor}} - {{event?.eventType?.localizedMessage }} +
  • + {{ + hist.values[0]?.dates[0]| timestampToDate | localizedDate: 'dd. MMMM YYYY' }} +
    +
    + + + +
    +
    +
    +
    + + + + {{ action.localizedMessage }} + {{ + dayelement.dates[j] | timestampToDate | localizedDate: 'HH:mm' + }} + + + + +
    +
    +
    +
  • diff --git a/console/src/app/modules/changes/changes.component.scss b/console/src/app/modules/changes/changes.component.scss index de886493ee..a1d41be22b 100644 --- a/console/src/app/modules/changes/changes.component.scss +++ b/console/src/app/modules/changes/changes.component.scss @@ -21,54 +21,119 @@ } @mixin changes-theme($theme) { - .scroll-container { - max-height: 50vh; - overflow-y: scroll; + .scroll-container { + max-height: 50vh; + overflow-y: scroll; + border-bottom: 1px solid #ffffff20; + margin-bottom: 0.5rem; - .item { - box-sizing: border-box; - padding: .5rem; - margin: .25rem 0; - border-radius: .5rem; - display: flex; - flex-direction: column; + .date { + font-weight: 500; + font-size: 0.8rem; + display: block; + margin-bottom: .5rem; + } - .editor { - color: var(--grey); - font-size: 12px; - align-self: flex-end; - } + .item { + display: block; + padding: 10px 0; + font-size: 0.8rem; - .seq { - color: var(--grey); - font-size: 12px; - align-self: flex-end; - } + .row { + display: flex; + flex-direction: row; - .desc { - overflow-x: auto; - font-size: 14px; - } - /* stylelint-disable */ - $primary: map-get($theme, primary); - $primary-dark: mat-color($primary, A800); - /* stylelint-enable */ + .spacer { + width: 32px; + } + + .actions { + flex: 1; + display: flex; + flex-direction: column; + margin-top: -0.5rem; - &.change-item-back { - background-color: rgba($primary-dark, .93); - transition: background-color .3s cubic-bezier(.645, .045, .355, 1); - } + .action { + display: flex; + flex-direction: row; + align-items: center; + flex: 1; + + .icon { + width: 32px; + display: inline-block; + height: 1.2rem; + line-height: 1.2rem; + font-size: 1.2rem; + color: var(--grey); + } + + span { + flex: 1; + font-weight: 500; + font-size: 0.8rem; + overflow-x: hidden; + } + + .msg { + text-overflow: ellipsis; + } + + .block { + display: block; + } + + .restore { + visibility: hidden; + display: none; + opacity: 0; + margin-left: 1rem; + transform: opacity 0.2s ease-in-out; + } + + &:hover { + .restore { + visibility: visible; + display: inline-block; + opacity: 1; + color: #81868a; + + &[disabled] { + visibility: hidden; + } + + &:hover { + color: white; + } + } + } + } + } + + /* stylelint-disable */ + $primary: map-get($theme, primary); + $primary-dark: mat-color($primary, A800); + /* stylelint-enable */ + + &.change-item-back { + background-color: rgba($primary-dark, .93); + transition: background-color .3s cubic-bezier(.645, .045, .355, 1); + } + } + + .sp-wrapper { + padding: .5rem; + display: flex; + justify-content: center; + } + + .end-container { + font-size: 12px; + color: var(--grey); + font-size: 14px; + margin: 1rem 0; + color: var(--grey); + } + } } - - .sp-wrapper { - padding: .5rem; - display: flex; - justify-content: center; - } - - .end-container { - font-size: 12px; - color: var(--grey); - } - } -} +} \ No newline at end of file diff --git a/console/src/app/modules/changes/changes.component.ts b/console/src/app/modules/changes/changes.component.ts index 58001fd7ae..c3fba97f57 100644 --- a/console/src/app/modules/changes/changes.component.ts +++ b/console/src/app/modules/changes/changes.component.ts @@ -4,6 +4,8 @@ import { catchError, debounceTime, scan, take, takeUntil, tap } from 'rxjs/opera import { Change, Changes } from 'src/app/proto/generated/management_pb'; import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; import { ManagementService } from 'src/app/services/mgmt.service'; +import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; +import { KeyValue } from '@angular/common'; export enum ChangeType { MYUSER = 'myuser', @@ -13,6 +15,18 @@ export enum ChangeType { APP = 'app', } +export interface MappedChange { + key: string, + values: Array<{ + data: any[]; + dates: Timestamp.AsObject[]; + editorId: string; + editorName: string; + eventTypes: Array<{ key: string; localizedMessage: string; }>; + sequences: number[]; + }>; +} + @Component({ selector: 'app-changes', templateUrl: './changes.component.html', @@ -31,7 +45,7 @@ export class ChangesComponent implements OnInit, OnDestroy { private _data: BehaviorSubject = new BehaviorSubject([]); loading: Observable = this._loading.asObservable(); - public data!: Observable; + public data!: Observable; public changes!: Changes.AsObject; private destroyed$: Subject = new Subject(); constructor(private mgmtUserService: ManagementService, private authUserService: GrpcAuthService) { @@ -52,6 +66,7 @@ export class ChangesComponent implements OnInit, OnDestroy { } public scrollHandler(e: any): void { + console.log('bottom'); if (e === 'bottom') { this.more(); } @@ -83,6 +98,7 @@ export class ChangesComponent implements OnInit, OnDestroy { private more(): void { const cursor = this.getCursor(); + console.log('cursor' + cursor); let more: Promise; @@ -105,9 +121,11 @@ export class ChangesComponent implements OnInit, OnDestroy { // Determines the snapshot to paginate query private getCursor(): number { const current = this._data.value; + if (current.length) { - return !this.sortDirectionAsc ? current[0].sequence : - current[current.length - 1].sequence; + const lastElementValues = current[current.length - 1].values; + const seq = lastElementValues[lastElementValues.length - 1].sequences; + return seq[seq.length - 1]; } return 0; } @@ -125,8 +143,10 @@ export class ChangesComponent implements OnInit, OnDestroy { take(1), tap((res: Changes) => { const values = res.toObject().changesList; + const mapped = this.mapChanges(values); // update source with new values, done loading - this._data.next(values); + // this._data.next(values); + this._data.next(mapped); this._loading.next(false); @@ -143,4 +163,85 @@ export class ChangesComponent implements OnInit, OnDestroy { ).subscribe(); } } + + mapChanges(changes: Change.AsObject[]) { + const splitted: { [editorId: string]: any[]; } = {}; + changes.forEach((change) => { + if (change.changeDate) { + const index = `${this.getDateString(change.changeDate)}`;//`${this.getDateString(change.changeDate)}:${change.editorId}`; + + if (index) { + if (splitted[index]) { + const userData: any = { + editor: change.editor, + editorId: change.editorId, + editorName: change.editor, + + dates: [change.changeDate], + data: [change.data], + eventTypes: [change.eventType], + sequences: [change.sequence], + }; + const lastIndex = splitted[index].length - 1; + if (lastIndex > -1 && splitted[index][lastIndex].editor === change.editor) { + splitted[index][lastIndex].dates.push(change.changeDate); + splitted[index][lastIndex].data.push(change.data); + splitted[index][lastIndex].eventTypes.push(change.eventType); + splitted[index][lastIndex].sequences.push(change.sequence); + } else { + splitted[index].push(userData); + } + } else { + splitted[index] = [ + { + editor: change.editor, + editorId: change.editorId, + editorName: change.editor, + + dates: [change.changeDate], + data: [change.data], + eventTypes: [change.eventType], + sequences: [change.sequence], + } + ]; + } + } + } + }); + const arr = Object.keys(splitted).map(key => { + return { key: key, values: splitted[key] }; + }); + + arr.sort((a, b) => { + return parseFloat(b.key) - parseFloat(a.key); + }); + + // console.log(arr); + return arr; + } + + getDateString(ts: Timestamp.AsObject) { + const date = new Date(ts.seconds * 1000 + ts.nanos / 1000 / 1000); + return date.getUTCFullYear() + this.pad(date.getUTCMonth() + 1) + this.pad(date.getUTCDate()); + } + + getTimestampIndex(date: any): number { + const ts: Date = new Date(date.seconds * 1000 + date.nanos / 1000 / 1000); + console.log(ts); + return ts.getTime(); + } + + pad(n: number): string { + return n < 10 ? '0' + n : n.toString(); + } + + // Order by ascending property value + valueAscOrder = (a: KeyValue, b: KeyValue): number => { + return a.value.localeCompare(b.value); + }; + + // Order by descending property key + keyDescOrder = (a: KeyValue, b: KeyValue): number => { + return a.key > b.key ? -1 : (b.key > a.key ? 1 : 0); + }; } diff --git a/console/src/app/modules/changes/changes.module.ts b/console/src/app/modules/changes/changes.module.ts index c9298c72f4..eb1af61fc8 100644 --- a/console/src/app/modules/changes/changes.module.ts +++ b/console/src/app/modules/changes/changes.module.ts @@ -10,6 +10,7 @@ import { ScrollableModule } from 'src/app/directives/scrollable/scrollable.modul import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module'; import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module'; +import { AvatarModule } from '../avatar/avatar.module'; import { ChangesComponent } from './changes.component'; @@ -30,6 +31,7 @@ import { ChangesComponent } from './changes.component'; LocalizedDatePipeModule, TimestampToDatePipeModule, MatTooltipModule, + AvatarModule ], exports: [ ChangesComponent, diff --git a/console/src/app/modules/client-keys/client-keys.component.html b/console/src/app/modules/client-keys/client-keys.component.html new file mode 100644 index 0000000000..da53785d5a --- /dev/null +++ b/console/src/app/modules/client-keys/client-keys.component.html @@ -0,0 +1,66 @@ + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + {{ 'USER.MACHINE.ID' | translate }} {{key?.id}} {{ 'USER.MACHINE.TYPE' | translate }} {{'USER.MACHINE.KEYTYPES.'+key?.type | translate}} {{ 'USER.MACHINE.CREATIONDATE' | translate }} + {{key.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}} + {{ 'USER.MACHINE.EXPIRATIONDATE' | translate }} + {{key.expirationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm'}} +
    + +
    +
    \ No newline at end of file diff --git a/console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.scss b/console/src/app/modules/client-keys/client-keys.component.scss similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.scss rename to console/src/app/modules/client-keys/client-keys.component.scss diff --git a/console/src/app/modules/client-keys/client-keys.component.spec.ts b/console/src/app/modules/client-keys/client-keys.component.spec.ts new file mode 100644 index 0000000000..c78b6eed39 --- /dev/null +++ b/console/src/app/modules/client-keys/client-keys.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { ClientKeysComponent } from './client-keys.component'; + +describe('ClientKeysComponent', () => { + let component: ClientKeysComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [ClientKeysComponent], + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ClientKeysComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/client-keys/client-keys.component.ts b/console/src/app/modules/client-keys/client-keys.component.ts new file mode 100644 index 0000000000..e159257a84 --- /dev/null +++ b/console/src/app/modules/client-keys/client-keys.component.ts @@ -0,0 +1,141 @@ +import { SelectionModel } from '@angular/cdk/collections'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { MatTableDataSource } from '@angular/material/table'; +import { TranslateService } from '@ngx-translate/core'; +import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; +import { Moment } from 'moment'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { AuthNKeyType, ClientKeySearchResponse, ClientKeyView, MachineKeySearchResponse, MachineKeyType, MachineKeyView } from 'src/app/proto/generated/management_pb'; +import { ManagementService } from 'src/app/services/mgmt.service'; +import { ToastService } from 'src/app/services/toast.service'; + +import { AddKeyDialogComponent, AddKeyDialogType } from 'src/app/modules/add-key-dialog/add-key-dialog.component'; +import { ShowKeyDialogComponent } from 'src/app/modules/show-key-dialog/show-key-dialog.component'; + +@Component({ + selector: 'app-client-keys', + templateUrl: './client-keys.component.html', + styleUrls: ['./client-keys.component.scss'], +}) +export class ClientKeysComponent implements OnInit { + @Input() projectId!: string; + @Input() appId!: string; + + @ViewChild(MatPaginator) public paginator!: MatPaginator; + public dataSource: MatTableDataSource = new MatTableDataSource(); + public selection: SelectionModel = new SelectionModel(true, []); + public keyResult!: MachineKeySearchResponse.AsObject | ClientKeySearchResponse.AsObject; + private loadingSubject: BehaviorSubject = new BehaviorSubject(false); + public loading$: Observable = this.loadingSubject.asObservable(); + @Input() public displayedColumns: string[] = ['select', 'id', 'type', 'creationDate', 'expirationDate']; + + @Output() public changedSelection: EventEmitter> = new EventEmitter(); + + constructor(public translate: TranslateService, private mgmtService: ManagementService, private dialog: MatDialog, + private toast: ToastService) { + this.selection.changed.subscribe(() => { + this.changedSelection.emit(this.selection.selected); + }); + } + + public ngOnInit(): void { + this.getData(10, 0); + } + + + public isAllSelected(): boolean { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + public masterToggle(): void { + this.isAllSelected() ? + this.selection.clear() : + this.dataSource.data.forEach(row => this.selection.select(row)); + } + + + public changePage(event: PageEvent): void { + this.getData(event.pageSize, event.pageIndex * event.pageSize); + } + + public deleteSelectedKeys(): void { + const mappedDeletions = this.selection.selected.map(value => { + return this.mgmtService.DeleteClientKey(value.id, this.projectId, this.appId); + }); + Promise.all(mappedDeletions).then(() => { + this.selection.clear(); + this.toast.showInfo('USER.TOAST.SELECTEDKEYSDELETED', true); + this.getData(10, 0); + }).catch(error => { + this.toast.showError(error); + }); + } + + public openAddKey(): void { + const dialogRef = this.dialog.open(AddKeyDialogComponent, { + data: {}, + width: '400px', + }); + + dialogRef.afterClosed().subscribe(resp => { + if (resp) { + const type: AuthNKeyType = resp.type; + + let date: Timestamp | undefined; + + if (resp.date as Moment) { + const ts = new Timestamp(); + console.log(resp.date.toDate()); + const milliseconds = resp.date.toDate().getTime(); + const seconds = Math.abs(milliseconds / 1000); + const nanos = (milliseconds - seconds * 1000) * 1000 * 1000; + ts.setSeconds(seconds); + ts.setNanos(nanos); + date = ts; + } + + if (type) { + return this.mgmtService.addClientKey(this.projectId, this.appId, type, date).then((response) => { + if (response) { + setTimeout(() => { + this.refreshPage(); + }, 1000); + + this.dialog.open(ShowKeyDialogComponent, { + data: { + key: response.toObject(), + type: AddKeyDialogType.AUTHNKEY + }, + width: '400px', + }); + } + }).catch((error: any) => { + this.toast.showError(error); + }); + } + } + }); + } + + private async getData(limit: number, offset: number): Promise { + this.loadingSubject.next(true); + if (this.projectId && this.appId) { + this.mgmtService.SearchClientKeys(this.projectId, this.appId, limit, offset).then(resp => { + this.keyResult = resp.toObject(); + this.dataSource.data = this.keyResult.resultList; + this.loadingSubject.next(false); + }).catch((error: any) => { + this.toast.showError(error); + this.loadingSubject.next(false); + }); + } + } + + public refreshPage(): void { + this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize); + } +} diff --git a/console/src/app/modules/client-keys/client-keys.module.ts b/console/src/app/modules/client-keys/client-keys.module.ts new file mode 100644 index 0000000000..1b0064d60d --- /dev/null +++ b/console/src/app/modules/client-keys/client-keys.module.ts @@ -0,0 +1,58 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatTableModule } from '@angular/material/table'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { TranslateModule } from '@ngx-translate/core'; +import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; +import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; +import { CardModule } from '../card/card.module'; +import { InputModule } from '../input/input.module'; +import { RefreshTableModule } from '../refresh-table/refresh-table.module'; + +import { ClientKeysComponent } from './client-keys.component'; +import { ShowKeyDialogModule } from '../show-key-dialog/show-key-dialog.module'; +import { AddKeyDialogModule } from 'src/app/modules/add-key-dialog/add-key-dialog.module'; +import { RouterModule } from '@angular/router'; +import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module'; +import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module'; + + +@NgModule({ + declarations: [ + ClientKeysComponent, + ], + imports: [ + CommonModule, + RouterModule, + FormsModule, + MatButtonModule, + MatDialogModule, + HasRoleModule, + CardModule, + MatTableModule, + MatPaginatorModule, + MatIconModule, + MatProgressSpinnerModule, + MatCheckboxModule, + MatTooltipModule, + HasRolePipeModule, + TimestampToDatePipeModule, + LocalizedDatePipeModule, + TranslateModule, + RefreshTableModule, + InputModule, + ShowKeyDialogModule, + AddKeyDialogModule, + ], + exports: [ + ClientKeysComponent, + ], +}) +export class ClientKeysModule { } diff --git a/console/src/app/modules/idp-table/idp-table.component.html b/console/src/app/modules/idp-table/idp-table.component.html index 2e9cb06291..9e48ce4f35 100644 --- a/console/src/app/modules/idp-table/idp-table.component.html +++ b/console/src/app/modules/idp-table/idp-table.component.html @@ -29,21 +29,19 @@ - - -
    - {{idp.name.charAt(0)}} -
    -
    + google
    {{ 'IDP.NAME' | translate }} - {{idp?.name}} + {{idp?.name}} + @@ -59,19 +57,24 @@ {{ 'IDP.STATE' | translate }} - {{ 'IDP.STATES.'+idp.state | translate }} + {{ + 'IDP.STATES.'+idp.state | translate }} + - + {{ 'IDP.CREATIONDATE' | translate }} - {{idp.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }} - - - - {{ 'IDP.CHANGEDATE' | translate }} - - {{idp.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }} +
    + {{ 'IDP.CREATIONDATE' | translate }}: + {{idp.creationDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }} +
    +
    + {{ 'IDP.CHANGEDATE' | translate }} + {{idp.changeDate | timestampToDate | localizedDate: 'dd. MMM, HH:mm' }} +
    +
    diff --git a/console/src/app/modules/idp-table/idp-table.component.scss b/console/src/app/modules/idp-table/idp-table.component.scss index 4c7626bcc0..5246b0e271 100644 --- a/console/src/app/modules/idp-table/idp-table.component.scss +++ b/console/src/app/modules/idp-table/idp-table.component.scss @@ -23,6 +23,15 @@ td { outline: none; + + img { + height: 30px; + width: 30px; + margin-left: 1rem; + border-radius: .5rem; + object-fit: contain; + margin-top: .5rem; + } } tr { @@ -88,3 +97,16 @@ tr { padding-bottom: .5rem; } } + + +.date-block { + margin: .5rem 0; + display: block; + min-width: 120px; + + .date-sub { + font-size: 13px; + display: block; + } +} + \ No newline at end of file diff --git a/console/src/app/modules/idp-table/idp-table.component.ts b/console/src/app/modules/idp-table/idp-table.component.ts index d75f49b8b2..c7fed50beb 100644 --- a/console/src/app/modules/idp-table/idp-table.component.ts +++ b/console/src/app/modules/idp-table/idp-table.component.ts @@ -5,8 +5,9 @@ import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { RouterLink } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; +import { Empty } from 'google-protobuf/google/protobuf/empty_pb'; import { BehaviorSubject, Observable } from 'rxjs'; -import { IdpSearchResponse as AdminIdpSearchResponse, IdpView as AdminIdpView } from 'src/app/proto/generated/admin_pb'; +import { IdpSearchResponse as AdminIdpSearchResponse, IdpState, IdpStylingType, IdpView as AdminIdpView } from 'src/app/proto/generated/admin_pb'; import { IdpProviderType, IdpView as MgmtIdpView } from 'src/app/proto/generated/management_pb'; import { AdminService } from 'src/app/services/admin.service'; import { ManagementService } from 'src/app/services/mgmt.service'; @@ -34,7 +35,9 @@ export class IdpTableComponent implements OnInit { public loading$: Observable = this.loadingSubject.asObservable(); public PolicyComponentServiceType: any = PolicyComponentServiceType; public IdpProviderType: any = IdpProviderType; - @Input() public displayedColumns: string[] = ['select', 'name', 'config', 'creationDate', 'changeDate', 'state']; + public IdpState: any = IdpState; + public IdpStylingType: any = IdpStylingType; + @Input() public displayedColumns: string[] = ['select', 'name', 'config', 'dates', 'state']; @Output() public changedSelection: EventEmitter> = new EventEmitter(); @@ -48,7 +51,7 @@ export class IdpTableComponent implements OnInit { ngOnInit(): void { this.getData(10, 0); if (this.serviceType === PolicyComponentServiceType.MGMT) { - this.displayedColumns = ['select', 'name', 'config', 'creationDate', 'changeDate', 'state', 'type']; + this.displayedColumns = ['select', 'name', 'config', 'dates', 'state', 'type']; } if (!this.disabled) { @@ -74,22 +77,28 @@ export class IdpTableComponent implements OnInit { } public deactivateSelectedIdps(): void { - this.selection.clear(); - Promise.all(this.selection.selected.map(value => { + const map: Promise[] = this.selection.selected.map(value => { return this.service.DeactivateIdpConfig(value.id); - })).then(() => { + }); + Promise.all(map).then(() => { + this.selection.clear(); this.toast.showInfo('IDP.TOAST.SELECTEDDEACTIVATED', true); this.refreshPage(); + }).catch(error => { + this.toast.showError(error); }); } public reactivateSelectedIdps(): void { - this.selection.clear(); - Promise.all(this.selection.selected.map(value => { + const map: Promise[] = this.selection.selected.map(value => { return this.service.ReactivateIdpConfig(value.id); - })).then(() => { + }); + Promise.all(map).then(() => { + this.selection.clear(); this.toast.showInfo('IDP.TOAST.SELECTEDREACTIVATED', true); this.refreshPage(); + }).catch(error => { + this.toast.showError(error); }); } diff --git a/console/src/app/modules/idp/idp.component.html b/console/src/app/modules/idp/idp.component.html index 1d580ec934..698cc513da 100644 --- a/console/src/app/modules/idp/idp.component.html +++ b/console/src/app/modules/idp/idp.component.html @@ -54,16 +54,24 @@ {{ 'IDP.CLIENTSECRET' | translate }} +
    + + {{ 'IDP.SCOPESLIST' | translate }} + + + + +
    - {{ 'IDP.SCOPESLIST' | translate }} - + {{scope}} cancel - diff --git a/console/src/app/modules/idp/idp.component.scss b/console/src/app/modules/idp/idp.component.scss index f176cdc6d2..2db8be8785 100644 --- a/console/src/app/modules/idp/idp.component.scss +++ b/console/src/app/modules/idp/idp.component.scss @@ -23,6 +23,12 @@ .formfield { flex: 1 1 auto; margin: 0 .5rem; + min-width: 150px; + + .chip { + border-radius: .5rem; + height: 40px; + } &.fullwidth { flex-basis: 100%; @@ -32,6 +38,24 @@ flex-basis: 100%; } } + + .line { + display: flex; + align-items: flex-end; + width: 100%; + + .formfield { + flex: 1; + + input { + margin: 0; + } + } + + button { + margin-bottom: 12px; + } + } } .btn-wrapper { @@ -41,7 +65,6 @@ .continue-button { margin-bottom: 4rem; display: block; - padding: .5rem 4rem; @media only screen and (max-width: 450px) { margin-top: 1rem; diff --git a/console/src/app/modules/links/links.component.html b/console/src/app/modules/links/links.component.html new file mode 100644 index 0000000000..af0435b761 --- /dev/null +++ b/console/src/app/modules/links/links.component.html @@ -0,0 +1,27 @@ +
    +
    {{'NEXTSTEPS.TITLE' | translate}}
    +
    + + +
    +
    {{ link.i18nTitle | translate }}
    +

    {{link.i18nDesc | translate}}

    + + + +
    +
    +
    +
    {{ link.i18nTitle | translate }}
    +

    {{link.i18nDesc | translate}}

    + + + +
    +
    +
    +
    \ No newline at end of file diff --git a/console/src/app/modules/links/links.component.scss b/console/src/app/modules/links/links.component.scss new file mode 100644 index 0000000000..1f799f6a0d --- /dev/null +++ b/console/src/app/modules/links/links.component.scss @@ -0,0 +1,59 @@ +.next-steps { + margin-top: 1rem; + h5 { + text-transform: uppercase; + font-size: 14px; + color: var(--grey); + } + + .row { + width: 100%; + display: flex; + overflow-x: auto; + padding-bottom: .5rem; + + .step { + min-width: 220px; + max-width: 280px; + padding: 1rem; + margin: 0 .5rem; + border: 1px solid var(--grey); + border-radius: .5rem; + display: flex; + flex-direction: column; + align-items: center; + box-sizing: border-box; + flex: 1; + + h6 { + font-size: 1rem; + text-align: center; + margin: 0 0 1rem 0; + } + + p { + font-size: 14px; + text-align: center; + color: var(--grey); + } + + .fill-space { + flex: 1; + } + + button { + display: block; + margin: auto; + } + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } + + } +} \ No newline at end of file diff --git a/console/src/app/modules/links/links.component.spec.ts b/console/src/app/modules/links/links.component.spec.ts new file mode 100644 index 0000000000..b17ab4ce4b --- /dev/null +++ b/console/src/app/modules/links/links.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LinksComponent } from './links.component'; + +describe('LinksComponent', () => { + let component: LinksComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LinksComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LinksComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/links/links.component.ts b/console/src/app/modules/links/links.component.ts new file mode 100644 index 0000000000..d122f43f84 --- /dev/null +++ b/console/src/app/modules/links/links.component.ts @@ -0,0 +1,24 @@ +import { Component, Input, OnInit } from '@angular/core'; + + +export interface CnslLinks { + i18nTitle: string; + i18nDesc: string; + routerLink?: any; + href?: string; + withRole?: Array; +} + +@Component({ + selector: 'cnsl-links', + templateUrl: './links.component.html', + styleUrls: ['./links.component.scss'] +}) +export class LinksComponent implements OnInit { + @Input() links: Array = []; + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/console/src/app/modules/links/links.module.ts b/console/src/app/modules/links/links.module.ts new file mode 100644 index 0000000000..421b12a693 --- /dev/null +++ b/console/src/app/modules/links/links.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { LinksComponent } from './links.component'; +import { TranslateModule } from '@ngx-translate/core'; +import { RouterModule } from '@angular/router'; +import { MatButton, MatButtonModule } from '@angular/material/button'; +import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; + + + +@NgModule({ + declarations: [LinksComponent], + imports: [ + CommonModule, + TranslateModule, + RouterModule, + MatButtonModule, + HasRoleModule, + ], + exports: [ + LinksComponent, + ] +}) +export class LinksModule { } diff --git a/console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.html b/console/src/app/modules/machine-keys/machine-keys.component.html similarity index 94% rename from console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.html rename to console/src/app/modules/machine-keys/machine-keys.component.html index 30ffa383ec..7f1497effd 100644 --- a/console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.html +++ b/console/src/app/modules/machine-keys/machine-keys.component.html @@ -1,6 +1,6 @@ - +
    @@ -54,8 +54,7 @@ - +
    diff --git a/console/src/app/modules/machine-keys/machine-keys.component.scss b/console/src/app/modules/machine-keys/machine-keys.component.scss new file mode 100644 index 0000000000..bade0aa759 --- /dev/null +++ b/console/src/app/modules/machine-keys/machine-keys.component.scss @@ -0,0 +1,27 @@ + +.table-wrapper { + overflow: auto; + + .table, + .paginator { + width: 100%; + + td, + th { + padding: 0 1rem; + + &:first-child { + padding-left: 0; + padding-right: 1rem; + } + + &:last-child { + padding-right: 0; + } + } + } +} + +tr { + outline: none; +} diff --git a/console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.spec.ts b/console/src/app/modules/machine-keys/machine-keys.component.spec.ts similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.spec.ts rename to console/src/app/modules/machine-keys/machine-keys.component.spec.ts diff --git a/console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.ts b/console/src/app/modules/machine-keys/machine-keys.component.ts similarity index 80% rename from console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.ts rename to console/src/app/modules/machine-keys/machine-keys.component.ts index 07f85bee7c..c7fe2312fd 100644 --- a/console/src/app/pages/users/user-detail/machine-keys/machine-keys.component.ts +++ b/console/src/app/modules/machine-keys/machine-keys.component.ts @@ -7,12 +7,12 @@ import { TranslateService } from '@ngx-translate/core'; import { Timestamp } from 'google-protobuf/google/protobuf/timestamp_pb'; import { Moment } from 'moment'; import { BehaviorSubject, Observable } from 'rxjs'; -import { MachineKeySearchResponse, MachineKeyType, MachineKeyView } from 'src/app/proto/generated/management_pb'; +import { ClientKeySearchResponse, MachineKeySearchResponse, MachineKeyType, MachineKeyView } from 'src/app/proto/generated/management_pb'; import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; -import { AddKeyDialogComponent } from './add-key-dialog/add-key-dialog.component'; -import { ShowKeyDialogComponent } from './show-key-dialog/show-key-dialog.component'; +import { AddKeyDialogComponent, AddKeyDialogType } from 'src/app/modules/add-key-dialog/add-key-dialog.component'; +import { ShowKeyDialogComponent } from 'src/app/modules/show-key-dialog/show-key-dialog.component'; @Component({ selector: 'app-machine-keys', @@ -21,17 +21,18 @@ import { ShowKeyDialogComponent } from './show-key-dialog/show-key-dialog.compon }) export class MachineKeysComponent implements OnInit { @Input() userId!: string; + @ViewChild(MatPaginator) public paginator!: MatPaginator; public dataSource: MatTableDataSource = new MatTableDataSource(); public selection: SelectionModel = new SelectionModel(true, []); - public keyResult!: MachineKeySearchResponse.AsObject; + public keyResult!: MachineKeySearchResponse.AsObject | ClientKeySearchResponse.AsObject; private loadingSubject: BehaviorSubject = new BehaviorSubject(false); public loading$: Observable = this.loadingSubject.asObservable(); @Input() public displayedColumns: string[] = ['select', 'id', 'type', 'creationDate', 'expirationDate']; @Output() public changedSelection: EventEmitter> = new EventEmitter(); - constructor(public translate: TranslateService, private userService: ManagementService, private dialog: MatDialog, + constructor(public translate: TranslateService, private mgmtService: ManagementService, private dialog: MatDialog, private toast: ToastService) { this.selection.changed.subscribe(() => { this.changedSelection.emit(this.selection.selected); @@ -62,7 +63,7 @@ export class MachineKeysComponent implements OnInit { public deleteSelectedKeys(): void { const mappedDeletions = this.selection.selected.map(value => { - return this.userService.DeleteMachineKey(value.id, this.userId); + return this.mgmtService.DeleteMachineKey(value.id, this.userId); }); Promise.all(mappedDeletions).then(() => { this.selection.clear(); @@ -97,7 +98,7 @@ export class MachineKeysComponent implements OnInit { } if (type) { - return this.userService.AddMachineKey(this.userId, type, date).then((response) => { + return this.mgmtService.AddMachineKey(this.userId, type, date).then((response) => { if (response) { setTimeout(() => { this.refreshPage(); @@ -106,6 +107,7 @@ export class MachineKeysComponent implements OnInit { this.dialog.open(ShowKeyDialogComponent, { data: { key: response.toObject(), + type: AddKeyDialogType.MACHINE }, width: '400px', }); @@ -121,14 +123,16 @@ export class MachineKeysComponent implements OnInit { private async getData(limit: number, offset: number): Promise { this.loadingSubject.next(true); - this.userService.SearchMachineKeys(this.userId, limit, offset).then(resp => { - this.keyResult = resp.toObject(); - this.dataSource.data = this.keyResult.resultList; - this.loadingSubject.next(false); - }).catch((error: any) => { - this.toast.showError(error); - this.loadingSubject.next(false); - }); + if (this.userId) { + this.mgmtService.SearchMachineKeys(this.userId, limit, offset).then(resp => { + this.keyResult = resp.toObject(); + this.dataSource.data = this.keyResult.resultList; + this.loadingSubject.next(false); + }).catch((error: any) => { + this.toast.showError(error); + this.loadingSubject.next(false); + }); + } } public refreshPage(): void { diff --git a/console/src/app/modules/machine-keys/machine-keys.module.ts b/console/src/app/modules/machine-keys/machine-keys.module.ts new file mode 100644 index 0000000000..ff724843f8 --- /dev/null +++ b/console/src/app/modules/machine-keys/machine-keys.module.ts @@ -0,0 +1,58 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDialogModule } from '@angular/material/dialog'; +import { MatIconModule } from '@angular/material/icon'; +import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatTableModule } from '@angular/material/table'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { TranslateModule } from '@ngx-translate/core'; +import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; +import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; +import { CardModule } from '../card/card.module'; +import { InputModule } from '../input/input.module'; +import { RefreshTableModule } from '../refresh-table/refresh-table.module'; + +import { MachineKeysComponent } from './machine-keys.component'; +import { ShowKeyDialogModule } from '../show-key-dialog/show-key-dialog.module'; +import { AddKeyDialogModule } from 'src/app/modules/add-key-dialog/add-key-dialog.module'; +import { RouterModule } from '@angular/router'; +import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module'; +import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module'; + + +@NgModule({ + declarations: [ + MachineKeysComponent, + ], + imports: [ + CommonModule, + RouterModule, + FormsModule, + MatButtonModule, + MatDialogModule, + HasRoleModule, + CardModule, + MatTableModule, + MatPaginatorModule, + MatIconModule, + MatProgressSpinnerModule, + MatCheckboxModule, + MatTooltipModule, + HasRolePipeModule, + TimestampToDatePipeModule, + LocalizedDatePipeModule, + TranslateModule, + RefreshTableModule, + InputModule, + ShowKeyDialogModule, + AddKeyDialogModule, + ], + exports: [ + MachineKeysComponent, + ], +}) +export class MachineKeysModule { } diff --git a/console/src/app/modules/meta-layout/meta-layout.component.scss b/console/src/app/modules/meta-layout/meta-layout.component.scss index 21165c92bc..e168359e37 100644 --- a/console/src/app/modules/meta-layout/meta-layout.component.scss +++ b/console/src/app/modules/meta-layout/meta-layout.component.scss @@ -19,9 +19,11 @@ position: relative; flex: 1 0 300px; padding: 1rem; + max-width: 300px; @media only screen and (min-width: 1500px) { flex-basis: 400px; + max-width: 400px; } .meta-content { diff --git a/console/src/app/modules/meta-layout/meta.scss b/console/src/app/modules/meta-layout/meta.scss index 5d996d3dc5..acd7ccc963 100644 --- a/console/src/app/modules/meta-layout/meta.scss +++ b/console/src/app/modules/meta-layout/meta.scss @@ -2,6 +2,8 @@ @import '~@angular/material/theming'; @mixin meta-theme($theme) { + $is-dark-theme: map-get($theme, is-dark); + .meta-details { margin-bottom: 1rem; border-bottom: 1px solid #81868a40; @@ -25,24 +27,6 @@ .second { font-size: 13px; } - - .state { - border-radius: 50vw; - padding: 2px .5rem; - letter-spacing: .05em; - font-size: 13px; - background-color: #8795a120; - - &.active { - background-color: #85d996; - color: black; - } - - &.inactive { - background-color: #ff8981; - color: black; - } - } } } diff --git a/console/src/app/modules/mfa-table/mfa-table.component.html b/console/src/app/modules/mfa-table/mfa-table.component.html index 3d45e4c2f5..563b785e10 100644 --- a/console/src/app/modules/mfa-table/mfa-table.component.html +++ b/console/src/app/modules/mfa-table/mfa-table.component.html @@ -7,9 +7,10 @@ remove_circle - {{(componentType == LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.': LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}} + {{(componentType == LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.': + LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}}
    -
    +
    add
    \ No newline at end of file diff --git a/console/src/app/modules/mfa-table/mfa-table.component.scss b/console/src/app/modules/mfa-table/mfa-table.component.scss index f0fe7e80a7..fe0619902a 100644 --- a/console/src/app/modules/mfa-table/mfa-table.component.scss +++ b/console/src/app/modules/mfa-table/mfa-table.component.scss @@ -9,6 +9,12 @@ margin: 0 -.5rem; .mfa { + background-color: #6a506e; + color: white; + } + + .mfa, + .new-mfa { border: 1px solid var(--grey); border-radius: .5rem; display: grid; @@ -23,10 +29,13 @@ .rm { position: absolute; - top: 0; - left: 0; + display: none; + top: -2px; + left: -2px; transform: translateX(-50%) translateY(-50%); cursor: pointer; + color: #f44336; + transition: all .2s ease; &[disabled] { display: none; @@ -35,7 +44,9 @@ &:not(.disabled) { &:hover { - background-color: #ffffff10; + .rm { + display: block; + } } } } diff --git a/console/src/app/modules/mfa-table/mfa-table.module.ts b/console/src/app/modules/mfa-table/mfa-table.module.ts index 8db0c2cf9d..7c4b890b4a 100644 --- a/console/src/app/modules/mfa-table/mfa-table.module.ts +++ b/console/src/app/modules/mfa-table/mfa-table.module.ts @@ -20,6 +20,7 @@ import { MfaTableComponent } from './mfa-table.component'; import { DialogAddTypeComponent } from './dialog-add-type/dialog-add-type.component'; import { InputModule } from '../input/input.module'; import { MatSelectModule } from '@angular/material/select'; +import { MatRippleModule } from '@angular/material/core'; @NgModule({ declarations: [MfaTableComponent, DialogAddTypeComponent], @@ -36,6 +37,7 @@ import { MatSelectModule } from '@angular/material/select'; TimestampToDatePipeModule, HasRoleModule, MatProgressSpinnerModule, + MatRippleModule, ], exports: [ MfaTableComponent, diff --git a/console/src/app/modules/policies/label-policy/label-policy.component.html b/console/src/app/modules/policies/label-policy/label-policy.component.html index 25da1dc81d..1033b9e401 100644 --- a/console/src/app/modules/policies/label-policy/label-policy.component.html +++ b/console/src/app/modules/policies/label-policy/label-policy.component.html @@ -1,4 +1,4 @@ -
    @@ -14,7 +14,9 @@
    - +
    + +
    \ No newline at end of file diff --git a/console/src/app/modules/policies/label-policy/label-policy.component.ts b/console/src/app/modules/policies/label-policy/label-policy.component.ts index f5852a429d..ad75709317 100644 --- a/console/src/app/modules/policies/label-policy/label-policy.component.ts +++ b/console/src/app/modules/policies/label-policy/label-policy.component.ts @@ -4,6 +4,8 @@ import { Subscription } from 'rxjs'; import { DefaultLabelPolicyUpdate, DefaultLabelPolicyView } from 'src/app/proto/generated/admin_pb'; import { AdminService } from 'src/app/services/admin.service'; import { ToastService } from 'src/app/services/toast.service'; +import { CnslLinks } from '../../links/links.component'; +import { IAM_COMPLEXITY_LINK, IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK } from '../../policy-grid/policy-links'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; @@ -19,6 +21,11 @@ export class LabelPolicyComponent implements OnDestroy { private sub: Subscription = new Subscription(); public PolicyComponentServiceType: any = PolicyComponentServiceType; + public nextLinks: CnslLinks[] = [ + IAM_COMPLEXITY_LINK, + IAM_POLICY_LINK, + IAM_LOGIN_POLICY_LINK, + ]; constructor( private route: ActivatedRoute, private toast: ToastService, diff --git a/console/src/app/modules/policies/label-policy/label-policy.module.ts b/console/src/app/modules/policies/label-policy/label-policy.module.ts index d05ba9acf7..d024565ff2 100644 --- a/console/src/app/modules/policies/label-policy/label-policy.module.ts +++ b/console/src/app/modules/policies/label-policy/label-policy.module.ts @@ -9,6 +9,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module'; import { InputModule } from 'src/app/modules/input/input.module'; +import { LinksModule } from '../../links/links.module'; import { LabelPolicyRoutingModule } from './label-policy-routing.module'; import { LabelPolicyComponent } from './label-policy.component'; @@ -27,6 +28,7 @@ import { LabelPolicyComponent } from './label-policy.component'; MatTooltipModule, TranslateModule, DetailLayoutModule, + LinksModule, ], }) export class LabelPolicyModule { } diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.html b/console/src/app/modules/policies/login-policy/login-policy.component.html index 930f2f869d..996c9ffcc0 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.component.html +++ b/console/src/app/modules/policies/login-policy/login-policy.component.html @@ -28,28 +28,36 @@ [(ngModel)]="loginData.allowUsernamePassword"> {{'POLICY.DATA.ALLOWUSERNAMEPASSWORD' | translate}} -

    {{'POLICY.DATA.ALLOWUSERNAMEPASSWORD_DESC' | translate}}

    + + {{'POLICY.DATA.ALLOWUSERNAMEPASSWORD_DESC' | translate}} +
    {{'POLICY.DATA.ALLOWREGISTER' | translate}} -

    {{'POLICY.DATA.ALLOWREGISTER_DESC' | translate}}

    + + {{'POLICY.DATA.ALLOWREGISTER_DESC' | translate}} +
    {{'POLICY.DATA.ALLOWEXTERNALIDP' | translate}} -

    {{'POLICY.DATA.ALLOWEXTERNALIDP_DESC' | translate}}

    + + {{'POLICY.DATA.ALLOWEXTERNALIDP_DESC' | translate}} +
    {{'POLICY.DATA.FORCEMFA' | translate}} -

    {{'POLICY.DATA.FORCEMFA_DESC' | translate}}

    + + {{'POLICY.DATA.FORCEMFA_DESC' | translate}} +
    @@ -92,20 +100,37 @@ remove_circle - {{idp.name}} - {{ 'IDP.TYPE' | translate }}: {{ 'IDP.TYPES.'+idp.type | translate }} - {{ 'IDP.ID' | translate }}: {{idp.idpConfigId}} +
    + google +
    + {{idp.name}} + {{ 'IDP.TYPE' | translate }}: {{ 'IDP.TYPES.'+idp.type | translate }} + {{ 'IDP.ID' | translate }}: {{idp.idpConfigId}} +
    +
    -
    +
    add
    -

    {{ 'IDP.LIST.TITLE' | translate }}

    -

    {{ 'IDP.LIST.DESCRIPTION' | translate }}

    - - + +
    + + + + + +
    + + +
    + + + \ No newline at end of file diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.scss b/console/src/app/modules/policies/login-policy/login-policy.component.scss index 5d2b27fbc2..ec8290ef7e 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.component.scss +++ b/console/src/app/modules/policies/login-policy/login-policy.component.scss @@ -15,18 +15,17 @@ margin: .3rem 0; } - p { - margin-top: .5rem; - font-size: 14px; - color: var(--grey); + .info { + margin-bottom: 1rem; + display: block; } } } .save-button { - margin-top: 3rem; + margin-bottom: 3rem; + float: right; display: block; - padding: .5rem 4rem; } .idp-table-card { @@ -46,6 +45,33 @@ display: flex; margin: 0 -.5rem; + .idp { + background-color: #506e6e; + color: white; + + .line { + display: flex; + align-items: center; + + img { + height: 30px; + width: 30px; + margin-right: 1rem; + border-radius: .5rem; + object-fit: contain; + } + + div { + flex: 1; + display: block; + + * { + display: block; + } + } + } + } + .idp, .new-idp { display: grid; @@ -68,15 +94,18 @@ padding: 2px; } - .meta { + .meta-info { font-size: 12px; - color: var(--grey); + color: #fafafa; } .rm { + color: #f44336; position: absolute; - top: 0; - left: 0; + display: none; + top: -2px; + transition: all .2s ease; + left: -2px; transform: translateX(-50%) translateY(-50%); cursor: pointer; @@ -86,11 +115,13 @@ } &:not(.disabled) { - &:hover { - background-color: #ffffff10; - } + &:hover { + .rm { + display: block; + } + } } - + img { height: 100%; width: 100%; @@ -102,6 +133,6 @@ .divider { width: 100%; height: 1px; - background-color: var(--grey); + background-color: rgba(var(--grey), .5); margin: 1rem 0; } diff --git a/console/src/app/modules/policies/login-policy/login-policy.component.ts b/console/src/app/modules/policies/login-policy/login-policy.component.ts index 9bb05c39a5..32f1ee3ac5 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.component.ts +++ b/console/src/app/modules/policies/login-policy/login-policy.component.ts @@ -9,6 +9,7 @@ import { DefaultLoginPolicyRequest, DefaultLoginPolicyView, IdpProviderView as AdminIdpProviderView, + IdpStylingType, IdpView as AdminIdpView, PasswordlessType as AdminPasswordlessType, } from 'src/app/proto/generated/admin_pb'; @@ -24,6 +25,8 @@ import { import { AdminService } from 'src/app/services/admin.service'; import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; +import { CnslLinks } from '../../links/links.component'; +import { IAM_COMPLEXITY_LINK, IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK, ORG_COMPLEXITY_LINK, ORG_IAM_POLICY_LINK } from '../../policy-grid/policy-links'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; import { AddIdpDialogComponent } from './add-idp-dialog/add-idp-dialog.component'; @@ -46,6 +49,9 @@ export class LoginPolicyComponent implements OnDestroy { public loading: boolean = false; public disabled: boolean = true; + + public IdpStylingType: any = IdpStylingType; + public nextLinks: CnslLinks[] = []; constructor( private route: ActivatedRoute, private toast: ToastService, @@ -59,11 +65,20 @@ export class LoginPolicyComponent implements OnDestroy { this.service = this.injector.get(ManagementService as Type); this.passwordlessTypes = [MgmtPasswordlessType.PASSWORDLESSTYPE_ALLOWED, MgmtPasswordlessType.PASSWORDLESSTYPE_NOT_ALLOWED]; + this.nextLinks = [ + ORG_COMPLEXITY_LINK, + ORG_IAM_POLICY_LINK, + ]; break; case PolicyComponentServiceType.ADMIN: this.service = this.injector.get(AdminService as Type); this.passwordlessTypes = [AdminPasswordlessType.PASSWORDLESSTYPE_ALLOWED, AdminPasswordlessType.PASSWORDLESSTYPE_NOT_ALLOWED]; + this.nextLinks = [ + IAM_COMPLEXITY_LINK, + IAM_POLICY_LINK, + IAM_LABEL_LINK, + ]; break; } @@ -207,7 +222,7 @@ export class LoginPolicyComponent implements OnDestroy { switch (this.serviceType) { case PolicyComponentServiceType.MGMT: (this.service as ManagementService).RemoveIdpProviderFromLoginPolicy(idp.idpConfigId).then(() => { - const index = this.idps.findIndex(temp => temp === idp); + const index = (this.idps as MgmtIdpProviderView.AsObject[]).findIndex(temp => temp === idp); if (index > -1) { this.idps.splice(index, 1); } @@ -215,7 +230,7 @@ export class LoginPolicyComponent implements OnDestroy { break; case PolicyComponentServiceType.ADMIN: (this.service as AdminService).RemoveIdpProviderFromDefaultLoginPolicy(idp.idpConfigId).then(() => { - const index = this.idps.findIndex(temp => temp === idp); + const index = (this.idps as AdminIdpProviderView.AsObject[]).findIndex(temp => temp === idp); if (index > -1) { this.idps.splice(index, 1); } diff --git a/console/src/app/modules/policies/login-policy/login-policy.module.ts b/console/src/app/modules/policies/login-policy/login-policy.module.ts index a53e209629..f4186d21c0 100644 --- a/console/src/app/modules/policies/login-policy/login-policy.module.ts +++ b/console/src/app/modules/policies/login-policy/login-policy.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; +import { MatRippleModule } from '@angular/material/core'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSelectModule } from '@angular/material/select'; @@ -15,6 +16,8 @@ import { IdpTableModule } from 'src/app/modules/idp-table/idp-table.module'; import { InputModule } from 'src/app/modules/input/input.module'; import { MfaTableModule } from 'src/app/modules/mfa-table/mfa-table.module'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; +import { InfoSectionModule } from '../../info-section/info-section.module'; +import { LinksModule } from '../../links/links.module'; import { AddIdpDialogModule } from './add-idp-dialog/add-idp-dialog.module'; import { LoginPolicyRoutingModule } from './login-policy-routing.module'; @@ -25,6 +28,7 @@ import { LoginPolicyComponent } from './login-policy.component'; imports: [ LoginPolicyRoutingModule, CommonModule, + InfoSectionModule, FormsModule, CardModule, InputModule, @@ -41,6 +45,8 @@ import { LoginPolicyComponent } from './login-policy.component'; MfaTableModule, MatProgressSpinnerModule, MatSelectModule, + MatRippleModule, + LinksModule, ], }) export class LoginPolicyModule { } diff --git a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.html b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.html index c82e381e89..92968ac91e 100644 --- a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.html +++ b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.html @@ -20,7 +20,9 @@
    - +
    + + \ No newline at end of file diff --git a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.scss b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.scss index 8167148521..c90c5d0d07 100644 --- a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.scss +++ b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.scss @@ -37,6 +37,5 @@ button { margin-top: 3rem; display: block; - padding: .5rem 4rem; } } diff --git a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.ts b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.ts index ba6d15b398..408866a560 100644 --- a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.ts +++ b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.component.ts @@ -9,6 +9,8 @@ import { AdminService } from 'src/app/services/admin.service'; import { ManagementService } from 'src/app/services/mgmt.service'; import { StorageService } from 'src/app/services/storage.service'; import { ToastService } from 'src/app/services/toast.service'; +import { CnslLinks } from '../../links/links.component'; +import { IAM_COMPLEXITY_LINK, IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, ORG_LOGIN_POLICY_LINK, ORG_COMPLEXITY_LINK } from '../../policy-grid/policy-links'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; @@ -28,7 +30,7 @@ export class OrgIamPolicyComponent implements OnDestroy { private org!: Org.AsObject; public PolicyComponentServiceType: any = PolicyComponentServiceType; - + public nextLinks: Array = []; constructor( private route: ActivatedRoute, private toast: ToastService, @@ -44,6 +46,16 @@ export class OrgIamPolicyComponent implements OnDestroy { this.serviceType = data.serviceType; if (this.serviceType === PolicyComponentServiceType.MGMT) { this.managementService = this.injector.get(ManagementService as Type); + this.nextLinks = [ + ORG_COMPLEXITY_LINK, + ORG_LOGIN_POLICY_LINK, + ]; + } else { + this.nextLinks = [ + IAM_COMPLEXITY_LINK, + IAM_LOGIN_POLICY_LINK, + IAM_LABEL_LINK, + ]; } return this.route.params; })).subscribe(_ => { diff --git a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.module.ts b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.module.ts index b865faab4e..9b32677830 100644 --- a/console/src/app/modules/policies/org-iam-policy/org-iam-policy.module.ts +++ b/console/src/app/modules/policies/org-iam-policy/org-iam-policy.module.ts @@ -9,6 +9,8 @@ import { TranslateModule } from '@ngx-translate/core'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module'; import { InputModule } from 'src/app/modules/input/input.module'; +import { InfoSectionModule } from '../../info-section/info-section.module'; +import { LinksModule } from '../../links/links.module'; import { OrgIamPolicyRoutingModule } from './org-iam-policy-routing.module'; import { OrgIamPolicyComponent } from './org-iam-policy.component'; @@ -25,8 +27,10 @@ import { OrgIamPolicyComponent } from './org-iam-policy.component'; MatIconModule, HasRoleModule, MatTooltipModule, + InfoSectionModule, TranslateModule, DetailLayoutModule, + LinksModule ], }) export class OrgIamPolicyModule { } diff --git a/console/src/app/modules/policies/password-age-policy/password-age-policy.component.scss b/console/src/app/modules/policies/password-age-policy/password-age-policy.component.scss index 6c63cab893..9c3b5df86b 100644 --- a/console/src/app/modules/policies/password-age-policy/password-age-policy.component.scss +++ b/console/src/app/modules/policies/password-age-policy/password-age-policy.component.scss @@ -34,6 +34,5 @@ button { margin-top: 3rem; display: block; - padding: .5rem 4rem; } } diff --git a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html index 64201a9d6c..9b093a419b 100644 --- a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html +++ b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.html @@ -16,6 +16,7 @@
    + {{'POLICY.DATA.MINLENGTH' | translate}}
    @@ -29,18 +30,21 @@
    + {{'POLICY.DATA.HASNUMBER' | translate}}
    + {{'POLICY.DATA.HASSYMBOL' | translate}}
    + {{'POLICY.DATA.HASLOWERCASE' | translate}}
    + {{'POLICY.DATA.HASUPPERCASE' | translate}}
    - +
    + + \ No newline at end of file diff --git a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.scss b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.scss index b629cc0eac..4460f6d245 100644 --- a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.scss +++ b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.scss @@ -18,6 +18,10 @@ align-items: center; padding: .3rem 0; + .icon { + margin-right: 1rem; + } + .left-desc { font-size: .9rem; } @@ -42,6 +46,5 @@ button { margin-top: 3rem; display: block; - padding: .5rem 4rem; } } diff --git a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.ts b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.ts index 0a578f8a11..eeab223485 100644 --- a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.ts +++ b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.component.ts @@ -7,6 +7,8 @@ import { PasswordComplexityPolicyView } from 'src/app/proto/generated/management import { AdminService } from 'src/app/services/admin.service'; import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; +import { CnslLinks } from '../../links/links.component'; +import { IAM_LABEL_LINK, IAM_LOGIN_POLICY_LINK, IAM_POLICY_LINK, ORG_IAM_POLICY_LINK, ORG_LOGIN_POLICY_LINK } from '../../policy-grid/policy-links'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; @@ -25,6 +27,7 @@ export class PasswordComplexityPolicyComponent implements OnDestroy { public PolicyComponentServiceType: any = PolicyComponentServiceType; public loading: boolean = false; + public nextLinks: CnslLinks[] = []; constructor( private route: ActivatedRoute, private toast: ToastService, @@ -36,9 +39,18 @@ export class PasswordComplexityPolicyComponent implements OnDestroy { switch (this.serviceType) { case PolicyComponentServiceType.MGMT: this.service = this.injector.get(ManagementService as Type); + this.nextLinks = [ + ORG_IAM_POLICY_LINK, + ORG_LOGIN_POLICY_LINK, + ]; break; case PolicyComponentServiceType.ADMIN: this.service = this.injector.get(AdminService as Type); + this.nextLinks = [ + IAM_POLICY_LINK, + IAM_LOGIN_POLICY_LINK, + IAM_LABEL_LINK, + ]; break; } diff --git a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.module.ts b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.module.ts index 5cd3cff6d6..28c141df27 100644 --- a/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.module.ts +++ b/console/src/app/modules/policies/password-complexity-policy/password-complexity-policy.module.ts @@ -10,6 +10,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module'; import { InputModule } from 'src/app/modules/input/input.module'; +import { LinksModule } from '../../links/links.module'; import { PasswordComplexityPolicyRoutingModule } from './password-complexity-policy-routing.module'; import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component'; @@ -29,6 +30,7 @@ import { PasswordComplexityPolicyComponent } from './password-complexity-policy. TranslateModule, DetailLayoutModule, MatProgressSpinnerModule, + LinksModule, ], }) export class PasswordComplexityPolicyModule { } diff --git a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html index 6dbad9aa7e..bea9af4823 100644 --- a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html +++ b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.component.html @@ -33,7 +33,7 @@
    - +
    \ No newline at end of file diff --git a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.module.ts b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.module.ts index 17356fa0da..d092c5cf02 100644 --- a/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.module.ts +++ b/console/src/app/modules/policies/password-lockout-policy/password-lockout-policy.module.ts @@ -9,6 +9,7 @@ import { TranslateModule } from '@ngx-translate/core'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; import { DetailLayoutModule } from 'src/app/modules/detail-layout/detail-layout.module'; import { InputModule } from 'src/app/modules/input/input.module'; +import { LinksModule } from '../../links/links.module'; import { PasswordLockoutPolicyRoutingModule } from './password-lockout-policy-routing.module'; import { PasswordLockoutPolicyComponent } from './password-lockout-policy.component'; diff --git a/console/src/app/modules/policy-grid/policy-grid.component.html b/console/src/app/modules/policy-grid/policy-grid.component.html index f6dddc116e..a1ea023a2b 100644 --- a/console/src/app/modules/policy-grid/policy-grid.component.html +++ b/console/src/app/modules/policy-grid/policy-grid.component.html @@ -19,6 +19,20 @@

    {{'POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate}}

    +
    + + + + + + + +
    +
    - -

    - {{'POLICY.LOGIN_POLICY.DESCRIPTION' | translate}}

    -
    +

    + {{'POLICY.LOGIN_POLICY.DESCRIPTION' | translate}}

    diff --git a/console/src/app/modules/policy-grid/policy-grid.component.scss b/console/src/app/modules/policy-grid/policy-grid.component.scss index e5c5420208..a8cc65d20a 100644 --- a/console/src/app/modules/policy-grid/policy-grid.component.scss +++ b/console/src/app/modules/policy-grid/policy-grid.component.scss @@ -21,6 +21,7 @@ h2 { min-height: 250px; padding: 1rem; height: 100%; + box-sizing: border-box; @media only screen and (max-width: 450px) { flex-basis: 100%; @@ -30,7 +31,7 @@ h2 { height: 60px; width: 60px; border-radius: 50%; - background: linear-gradient(40deg, rgb(129, 85, 185) 30%, #5469d4); + background: linear-gradient(40deg, rgb(129, 85, 185) 30%, #7b8ada); display: flex; align-items: center; justify-content: center; @@ -64,6 +65,13 @@ h2 { color: var(--grey); } + .icons { + margin-bottom: 1rem; + .icon { + margin-right: .5rem; + } + } + .fill-space { flex: 1; } diff --git a/console/src/app/modules/policy-grid/policy-grid.component.ts b/console/src/app/modules/policy-grid/policy-grid.component.ts index f5d0d3efba..ba66e493dc 100644 --- a/console/src/app/modules/policy-grid/policy-grid.component.ts +++ b/console/src/app/modules/policy-grid/policy-grid.component.ts @@ -1,5 +1,9 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { PolicyComponentType } from 'src/app/modules/policies/policy-component-types.enum'; +import { PasswordComplexityPolicyView as MgmtPasswordComplexityPolicyView } from 'src/app/proto/generated/management_pb'; +import { DefaultPasswordComplexityPolicyView as AdminPasswordComplexityPolicyView } from 'src/app/proto/generated/admin_pb'; +import { ManagementService } from 'src/app/services/mgmt.service'; +import { AdminService } from 'src/app/services/admin.service'; export enum PolicyGridType { ORG, @@ -11,9 +15,24 @@ export enum PolicyGridType { templateUrl: './policy-grid.component.html', styleUrls: ['./policy-grid.component.scss'], }) -export class PolicyGridComponent { +export class PolicyGridComponent implements OnInit { @Input() public type!: PolicyGridType; public PolicyComponentType: any = PolicyComponentType; public PolicyGridType: any = PolicyGridType; - constructor() { } + + public complexityPolicy!: MgmtPasswordComplexityPolicyView.AsObject | AdminPasswordComplexityPolicyView.AsObject | any; + + constructor(private mgmtService: ManagementService, private adminService: AdminService) { } + + public ngOnInit(): void { + if (this.type == PolicyGridType.ORG) { + this.mgmtService.GetDefaultPasswordComplexityPolicy().then((policy) => { + this.complexityPolicy = policy.toObject(); + }); + } else if (this.type == PolicyGridType.IAM) { + this.adminService.GetDefaultPasswordComplexityPolicy().then((policy) => { + this.complexityPolicy = policy.toObject(); + }); + } + } } diff --git a/console/src/app/modules/policy-grid/policy-grid.module.ts b/console/src/app/modules/policy-grid/policy-grid.module.ts index 6dd7f7d3a5..6dcd601fde 100644 --- a/console/src/app/modules/policy-grid/policy-grid.module.ts +++ b/console/src/app/modules/policy-grid/policy-grid.module.ts @@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { RouterModule } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; @@ -19,6 +20,7 @@ import { PolicyGridComponent } from './policy-grid.component'; RouterModule, MatButtonModule, MatIconModule, + MatTooltipModule, ], exports: [ PolicyGridComponent, diff --git a/console/src/app/modules/policy-grid/policy-links.ts b/console/src/app/modules/policy-grid/policy-links.ts new file mode 100644 index 0000000000..d466795fd3 --- /dev/null +++ b/console/src/app/modules/policy-grid/policy-links.ts @@ -0,0 +1,51 @@ +import { PolicyComponentType } from '../policies/policy-component-types.enum'; + +export const IAM_COMPLEXITY_LINK = { + i18nTitle: 'POLICY.PWD_COMPLEXITY.TITLE', + i18nDesc: 'POLICY.PWD_COMPLEXITY.DESCRIPTION', + routerLink: ['/iam', 'policy', PolicyComponentType.COMPLEXITY], + withRole: ['iam.policy.read'], +}; + +export const IAM_POLICY_LINK = { + i18nTitle: 'POLICY.IAM_POLICY.TITLE', + i18nDesc: 'POLICY.IAM_POLICY.DESCRIPTION', + routerLink: ['/iam', 'policy', PolicyComponentType.IAM], + withRole: ['iam.policy.read'], +}; + +export const IAM_LOGIN_POLICY_LINK = { + i18nTitle: 'POLICY.LOGIN_POLICY.TITLE', + i18nDesc: 'POLICY.LOGIN_POLICY.DESCRIPTION', + routerLink: ['/iam', 'policy', PolicyComponentType.LOGIN], + withRole: ['iam.policy.read'], +}; + +export const IAM_LABEL_LINK = { + i18nTitle: 'POLICY.LABEL.TITLE', + i18nDesc: 'POLICY.LABEL.DESCRIPTION', + routerLink: ['/iam', 'policy', PolicyComponentType.LABEL], + withRole: ['iam.policy.read'], +}; + + +export const ORG_COMPLEXITY_LINK = { + i18nTitle: 'POLICY.PWD_COMPLEXITY.TITLE', + i18nDesc: 'POLICY.PWD_COMPLEXITY.DESCRIPTION', + routerLink: ['/org', 'policy', PolicyComponentType.COMPLEXITY], + withRole: ['policy.read'], +}; + +export const ORG_IAM_POLICY_LINK = { + i18nTitle: 'POLICY.IAM_POLICY.TITLE', + i18nDesc: 'POLICY.IAM_POLICY.DESCRIPTION', + routerLink: ['/org', 'policy', PolicyComponentType.IAM], + withRole: ['iam.policy.read'], +}; + +export const ORG_LOGIN_POLICY_LINK = { + i18nTitle: 'POLICY.LOGIN_POLICY.TITLE', + i18nDesc: 'POLICY.LOGIN_POLICY.DESCRIPTION', + routerLink: ['/org', 'policy', PolicyComponentType.LOGIN], + withRole: ['policy.read'], +}; diff --git a/console/src/app/modules/project-roles/project-role-detail/project-role-detail.component.ts b/console/src/app/modules/project-roles/project-role-detail/project-role-detail.component.ts index 4213a2687d..cb6fa62a65 100644 --- a/console/src/app/modules/project-roles/project-role-detail/project-role-detail.component.ts +++ b/console/src/app/modules/project-roles/project-role-detail/project-role-detail.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { ManagementService } from 'src/app/services/mgmt.service'; @@ -9,7 +9,7 @@ import { ToastService } from 'src/app/services/toast.service'; templateUrl: './project-role-detail.component.html', styleUrls: ['./project-role-detail.component.scss'], }) -export class ProjectRoleDetailComponent implements OnInit { +export class ProjectRoleDetailComponent { public projectId: string = ''; public formGroup!: FormGroup; @@ -27,12 +27,9 @@ export class ProjectRoleDetailComponent implements OnInit { this.formGroup.patchValue(data.role); } - ngOnInit(): void { - } - submitForm(): void { if (this.formGroup.valid && this.key?.value && this.group?.value && this.displayName?.value) { - this.mgmtService.ChangeProjectRole(this.projectId, this.key.value, this.key.value, this.group.value) + this.mgmtService.ChangeProjectRole(this.projectId, this.key.value, this.displayName.value, this.group.value) .then(() => { this.toast.showInfo('PROJECT.TOAST.ROLECHANGED', true); this.dialogRef.close(true); diff --git a/console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.html b/console/src/app/modules/show-key-dialog/show-key-dialog.component.html similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.html rename to console/src/app/modules/show-key-dialog/show-key-dialog.component.html diff --git a/console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.scss b/console/src/app/modules/show-key-dialog/show-key-dialog.component.scss similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.scss rename to console/src/app/modules/show-key-dialog/show-key-dialog.component.scss diff --git a/console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.spec.ts b/console/src/app/modules/show-key-dialog/show-key-dialog.component.spec.ts similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.spec.ts rename to console/src/app/modules/show-key-dialog/show-key-dialog.component.spec.ts diff --git a/console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.ts b/console/src/app/modules/show-key-dialog/show-key-dialog.component.ts similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.component.ts rename to console/src/app/modules/show-key-dialog/show-key-dialog.component.ts diff --git a/console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.module.ts b/console/src/app/modules/show-key-dialog/show-key-dialog.module.ts similarity index 100% rename from console/src/app/pages/users/user-detail/machine-keys/show-key-dialog/show-key-dialog.module.ts rename to console/src/app/modules/show-key-dialog/show-key-dialog.module.ts diff --git a/console/src/app/pages/orgs/org-detail/org-detail.component.html b/console/src/app/pages/orgs/org-detail/org-detail.component.html index 8a2be81697..4cb8307c4c 100644 --- a/console/src/app/pages/orgs/org-detail/org-detail.component.html +++ b/console/src/app/pages/orgs/org-detail/org-detail.component.html @@ -40,13 +40,15 @@ {{ org.id }}
    - {{'ORG.PAGES.PRIMARYDOMAIN' | translate}} + {{'ORG.PAGES.PRIMARYDOMAIN' | translate}} {{primaryDomain}}
    - {{'ORG.PAGES.STATE' | translate}} - {{'ORG.STATE.'+org.state | translate}} + {{'ORG.PAGES.STATE' | translate}} + {{'ORG.STATE.'+org.state + | + translate}}
    diff --git a/console/src/app/pages/projects/apps/app-create/app-create.component.html b/console/src/app/pages/projects/apps/app-create/app-create.component.html index 567e85ddb2..901659fa17 100644 --- a/console/src/app/pages/projects/apps/app-create/app-create.component.html +++ b/console/src/app/pages/projects/apps/app-create/app-create.component.html @@ -15,7 +15,8 @@ {{'APP.OIDC.PROSWITCH' | translate}} - +
    {{'APP.OIDC.NAMEANDTYPESECTION' | translate}} @@ -29,8 +30,9 @@

    {{'APP.OIDC.TYPETITLE' | translate}}

    - + +
    @@ -42,10 +44,11 @@ - {{'APP.OIDC.AUTHMETHODSECTION' | translate}} + {{'APP.AUTHMETHODSECTION' | translate}} + [isOIDC]="appType?.value?.createType == AppCreateType.OIDC" + (selectedMethod)="authMethod?.setValue($event)">
    @@ -57,7 +60,8 @@ - + + {{'APP.OIDC.REDIRECTSECTION' | translate}}

    {{'APP.OIDC.REDIRECTTITLE' | translate}}

    @@ -68,8 +72,9 @@ {{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}

    + [getValues]="requestRedirectValuesSubject$" title="{{ 'APP.OIDC.REDIRECT' | translate }}">

    {{'APP.OIDC.POSTREDIRECTTITLE' | translate}}

    @@ -82,7 +87,9 @@ + [urisList]="oidcApp.postLogoutRedirectUrisList" title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}" + [getValues]="requestRedirectValuesSubject$" + [isNative]="oidcApp.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
    @@ -103,78 +110,94 @@ {{oidcApp.name}}
    -
    - - {{ 'APP.TYPE' | translate }} - - - {{'APP.OIDC.APPTYPE'+oidcApp.applicationType | translate}} - -
    -
    - - {{ 'APP.GRANT' | translate }} - - - [ - {{'APP.OIDC.GRANT'+element | translate}} - {{i < oidcApp.grantTypesList.length - 1 ? ', ' : '' }} ] - -
    -
    - - {{ 'APP.OIDC.RESPONSE' | translate }} - - - [ - {{('APP.OIDC.RESPONSE'+element | translate)}} - {{i < oidcApp.responseTypesList.length - 1 ? ', ' : '' }} ] - -
    -
    - - {{ 'APP.OIDC.AUTHMETHOD' | translate }} - - - - {{'APP.OIDC.AUTHMETHOD'+oidcApp?.authMethodType | translate}} + +
    + + {{ 'APP.TYPE' | translate }} - -
    + + {{'APP.OIDC.APPTYPE.'+oidcApp.applicationType | translate}} + +
    +
    + + {{ 'APP.GRANT' | translate }} + + + [ + {{'APP.OIDC.GRANT.'+element | translate}} + {{i < oidcApp.grantTypesList.length - 1 ? ', ' : '' }} ] + +
    +
    + + {{ 'APP.OIDC.RESPONSETYPE' | translate }} + + + [ + {{('APP.OIDC.RESPONSE.'+element | translate)}} + {{i < oidcApp.responseTypesList.length - 1 ? ', ' : '' }} ] + +
    -
    - - {{ 'APP.OIDC.REDIRECT' | translate }} - - - [ - {{redirect}} - {{i < oidcApp.redirectUrisList.length - 1 ? ', ' : '' }} ] +
    + + {{ 'APP.AUTHMETHOD' | translate }} -
    + + + {{'APP.OIDC.AUTHMETHOD.'+oidcApp?.authMethodType | translate}} + + +
    -
    - - {{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }} - - - [ - {{redirect}} - {{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} ] +
    + + {{ 'APP.OIDC.REDIRECT' | translate }} -
    + + [ + {{redirect}} + {{i < oidcApp.redirectUrisList.length - 1 ? ', ' : '' }} ] + +
    + +
    + + {{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }} + + + [ + {{redirect}} + {{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ' : '' }} ] + +
    + + + +
    + + {{ 'APP.AUTHMETHOD' | translate }} + + + + {{'APP.API.AUTHMETHOD.'+apiApp?.authMethodType | translate}} + + +
    +
    -
    -
    +
    {{ 'APP.NAME' | translate }} @@ -182,51 +205,59 @@ - {{ 'APP.OIDC.APPTYPE' | translate }} - - - {{ 'APP.OIDC.APPTYPE'+type.type | translate }} + {{ 'APP.TYPE' | translate }} + + + {{ appType.titleI18nKey | translate }} - - {{ 'APP.OIDC.GRANT' | translate }} - - - {{ ('APP.OIDC.GRANT' + grant.type) | translate }} - - - + + + {{ 'APP.OIDC.GRANTTYPE' | translate }} + + + {{ ('APP.OIDC.GRANT.' + grant.type) | translate }} + + + + + + {{ 'APP.OIDC.RESPONSETYPE' | translate }} + + + {{ 'APP.OIDC.RESPONSE.'+type.type | translate }} + + + + - {{ 'APP.OIDC.RESPONSE' | translate }} - - - {{ 'APP.OIDC.RESPONSE'+type.type | translate }} - - - - - - {{ 'APP.OIDC.AUTHMETHOD' | translate }} + {{ 'APP.AUTHMETHOD' | translate }} - - {{ 'APP.OIDC.AUTHMETHOD'+type.type | translate }} + + {{ 'APP.OIDC.AUTHMETHOD.'+type.type | translate }} + {{ 'APP.API.AUTHMETHOD.'+type.type | translate }} +
    +
    + title="{{ 'APP.OIDC.REDIRECT' | translate }}" [getValues]="requestRedirectValuesSubject$" + [isNative]="oidcApp.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE"> + title="{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}" + [getValues]="requestRedirectValuesSubject$" + [isNative]="oidcApp.applicationType == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
    diff --git a/console/src/app/pages/projects/apps/app-create/app-create.component.ts b/console/src/app/pages/projects/apps/app-create/app-create.component.ts index ce667d55d7..2175ed2b05 100644 --- a/console/src/app/pages/projects/apps/app-create/app-create.component.ts +++ b/console/src/app/pages/projects/apps/app-create/app-create.component.ts @@ -4,14 +4,17 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Params, Router } from '@angular/router'; -import { Subscription } from 'rxjs'; -import { debounceTime } from 'rxjs/operators'; +import { Subject, Subscription } from 'rxjs'; +import { debounceTime, takeUntil } from 'rxjs/operators'; import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component'; import { + APIApplicationCreate, + APIAuthMethodType, Application, OIDCApplicationCreate, OIDCApplicationType, OIDCAuthMethodType, + OIDCConfig, OIDCGrantType, OIDCResponseType, } from 'src/app/proto/generated/management_pb'; @@ -21,11 +24,15 @@ import { ToastService } from 'src/app/services/toast.service'; import { WEB_TYPE, NATIVE_TYPE, - USER_AGENT_TYPE + USER_AGENT_TYPE, + API_TYPE, + RadioItemAppType, + AppCreateType } from '../authtypes'; import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component'; -import { CODE_METHOD, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD } from '../authmethods'; +import { CODE_METHOD, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, BASIC_AUTH_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD } from '../authmethods'; +import { StepperSelectionEvent } from '@angular/cdk/stepper'; @Component({ @@ -35,10 +42,13 @@ import { CODE_METHOD, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METH }) export class AppCreateComponent implements OnInit, OnDestroy { private subscription?: Subscription; + private destroyed$: Subject = new Subject(); public devmode: boolean = false; public projectId: string = ''; public loading: boolean = false; + public oidcApp: OIDCApplicationCreate.AsObject = new OIDCApplicationCreate().toObject(); + public apiApp: APIApplicationCreate.AsObject = new APIApplicationCreate().toObject(); public oidcResponseTypes: { type: OIDCResponseType, checked: boolean; disabled: boolean; }[] = [ { type: OIDCResponseType.OIDCRESPONSETYPE_CODE, checked: false, disabled: false }, @@ -46,22 +56,30 @@ export class AppCreateComponent implements OnInit, OnDestroy { { type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN, checked: false, disabled: false }, ]; - public oidcAppTypes: any = [ + public oidcAppTypes: OIDCApplicationType[] = [ + OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, + OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE, + OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT, + ]; + public appTypes: any = [ WEB_TYPE, NATIVE_TYPE, USER_AGENT_TYPE, + API_TYPE, ]; public authMethods: RadioItemAuthType[] = [ PKCE_METHOD, CODE_METHOD, + PK_JWT_METHOD, POST_METHOD, ]; - public oidcAuthMethodType: { type: OIDCAuthMethodType, checked: boolean, disabled: boolean; }[] = [ - { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, checked: false, disabled: false }, - { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, checked: false, disabled: false }, - { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, checked: false, disabled: false }, + // set to oidc first + public authMethodTypes: { type: OIDCAuthMethodType | APIAuthMethodType, checked: boolean, disabled: boolean; api?: boolean; oidc?: boolean; }[] = [ + { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, checked: false, disabled: false, oidc: true }, + { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, checked: false, disabled: false, oidc: true }, + { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, checked: false, disabled: false, oidc: true }, ]; // stepper @@ -71,6 +89,7 @@ export class AppCreateComponent implements OnInit, OnDestroy { // devmode public form!: FormGroup; + public AppCreateType: any = AppCreateType; public OIDCApplicationType: any = OIDCApplicationType; public OIDCGrantType: any = OIDCGrantType; public OIDCAuthMethodType: any = OIDCAuthMethodType; @@ -87,6 +106,7 @@ export class AppCreateComponent implements OnInit, OnDestroy { ]; public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE]; + public requestRedirectValuesSubject$: Subject = new Subject(); constructor( private router: Router, @@ -101,57 +121,68 @@ export class AppCreateComponent implements OnInit, OnDestroy { name: ['', [Validators.required]], responseTypesList: ['', [Validators.required]], grantTypesList: ['', [Validators.required]], - applicationType: ['', [Validators.required]], + appType: ['', [Validators.required]], authMethodType: ['', [Validators.required]], }); - this.form.valueChanges.pipe(debounceTime(300)).subscribe((value) => { - this.oidcApp.name = this.formname?.value; - this.oidcApp.applicationType = this.formapplicationType?.value; - this.oidcApp.responseTypesList = this.formresponseTypesList?.value; - this.oidcApp.grantTypesList = this.formgrantTypesList?.value; - this.oidcApp.authMethodType = this.formauthMethodType?.value; - }); + this.initForm(); this.firstFormGroup = this.fb.group({ name: ['', [Validators.required]], - applicationType: [OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, [Validators.required]], + appType: [WEB_TYPE, [Validators.required]], }); this.firstFormGroup.valueChanges.subscribe(value => { if (this.firstFormGroup.valid) { this.oidcApp.name = this.name?.value; - this.oidcApp.applicationType = this.applicationType?.value; + this.apiApp.name = this.name?.value; - switch (this.applicationType?.value) { - case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE: - this.authMethods = [ - PKCE_METHOD, - ]; + if (this.isStepperOIDC) { + const oidcAppType = (this.appType?.value as RadioItemAppType).oidcApplicationType; + if (oidcAppType !== undefined) { + this.oidcApp.applicationType = oidcAppType; + } - // automatically set to PKCE and skip step - this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE]; - this.oidcApp.grantTypesList = [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE]; - this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE; + switch (this.oidcApp.applicationType) { + case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE: + this.authMethods = [ + PKCE_METHOD, + ]; - break; - case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB: - this.authMethods = [ - PKCE_METHOD, - CODE_METHOD, - POST_METHOD, - ]; + // automatically set to PKCE and skip step + this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE]; + this.oidcApp.grantTypesList = [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE]; + this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE; - this.authMethod?.setValue(PKCE_METHOD.key); - break; - case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT: - this.authMethods = [ - PKCE_METHOD, - IMPLICIT_METHOD, - ]; + break; + case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB: + // PK_JWT_METHOD.recommended = false; + this.authMethods = [ + PKCE_METHOD, + CODE_METHOD, + PK_JWT_METHOD, + POST_METHOD, + ]; - this.authMethod?.setValue(PKCE_METHOD.key); - break; + this.authMethod?.setValue(PKCE_METHOD.key); + break; + case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT: + this.authMethods = [ + PKCE_METHOD, + IMPLICIT_METHOD, + ]; + + this.authMethod?.setValue(PKCE_METHOD.key); + break; + } + } else if (this.isStepperAPI) { + // PK_JWT_METHOD.recommended = true; + this.authMethods = [ + PK_JWT_METHOD, + BASIC_AUTH_METHOD, + ]; + + this.authMethod?.setValue(PK_JWT_METHOD.key); } } }); @@ -162,10 +193,12 @@ export class AppCreateComponent implements OnInit, OnDestroy { this.secondFormGroup.valueChanges.subscribe(form => { const partialConfig = getPartialConfigFromAuthMethod(form.authMethod); - if (partialConfig) { - this.oidcApp.responseTypesList = partialConfig.responseTypesList ?? []; - this.oidcApp.grantTypesList = partialConfig.grantTypesList ?? []; - this.oidcApp.authMethodType = partialConfig.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE; + if (this.isStepperOIDC && partialConfig && partialConfig.oidc) { + this.oidcApp.responseTypesList = partialConfig.oidc?.responseTypesList ?? []; + this.oidcApp.grantTypesList = partialConfig.oidc?.grantTypesList ?? []; + this.oidcApp.authMethodType = partialConfig.oidc?.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE; + } else if (this.isStepperAPI && partialConfig && partialConfig.api) { + this.apiApp.authMethodType = partialConfig.api?.authMethodType ?? APIAuthMethodType.APIAUTHMETHODTYPE_BASIC; } }); } @@ -176,52 +209,135 @@ export class AppCreateComponent implements OnInit, OnDestroy { public ngOnDestroy(): void { this.subscription?.unsubscribe(); + this.destroyed$.next(); } - public changedAppType(type: OIDCApplicationType) { - this.firstFormGroup.controls['applicationType'].setValue(type); + public initForm(): void { + this.form.valueChanges.pipe( + takeUntil(this.destroyed$), + debounceTime(150)).subscribe(() => { + this.oidcApp.name = this.formname?.value; + this.apiApp.name = this.formname?.value; + + this.oidcApp.responseTypesList = this.formresponseTypesList?.value; + this.oidcApp.grantTypesList = this.formgrantTypesList?.value; + + this.oidcApp.authMethodType = this.formauthMethodType?.value; + this.apiApp.authMethodType = this.formauthMethodType?.value; + + const oidcAppType = (this.formappType?.value as RadioItemAppType).oidcApplicationType; + if (oidcAppType !== undefined) { + this.oidcApp.applicationType = oidcAppType; + } + }); + + this.formappType?.valueChanges.pipe(takeUntil(this.destroyed$)).subscribe(() => { + this.setDevFormValidators(); + }); } - public changedAppAuthMethod(methodKey: string) { - console.log(methodKey); - this.secondFormGroup.controls['authMethod'].setValue(methodKey); + public setDevFormValidators(): void { + if (this.isDevOIDC) { + const grantTypesControl = new FormControl('', [Validators.required]); + const responseTypesControl = new FormControl('', [Validators.required]); + + this.form.addControl('grantTypesList', grantTypesControl); + this.form.addControl('responseTypesList', responseTypesControl); + + this.authMethodTypes = [ + { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, checked: false, disabled: false, oidc: true }, + { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, checked: false, disabled: false, oidc: true }, + { type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, checked: false, disabled: false, oidc: true }, + ]; + this.authMethod?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC); + } else if (this.isDevAPI) { + this.form.removeControl('grantTypesList'); + this.form.removeControl('responseTypesList'); + + this.authMethodTypes = [ + { type: APIAuthMethodType.APIAUTHMETHODTYPE_PRIVATE_KEY_JWT, checked: false, disabled: false, api: true }, + { type: APIAuthMethodType.APIAUTHMETHODTYPE_BASIC, checked: false, disabled: false, api: true }, + ]; + this.authMethod?.setValue(APIAuthMethodType.APIAUTHMETHODTYPE_PRIVATE_KEY_JWT); + } + this.form.updateValueAndValidity(); + } + + public changeStep(event: StepperSelectionEvent) { + if (event.selectedIndex >= 2) { + this.requestRedirectValuesSubject$.next(); + }; } private async getData({ projectid }: Params): Promise { this.projectId = projectid; this.oidcApp.projectId = projectid; + this.apiApp.projectId = projectid; } public close(): void { this._location.back(); } - public saveOIDCApp(): void { - this.loading = true; - this.mgmtService - .CreateOIDCApp(this.oidcApp) - .then((data: Application) => { - this.loading = false; - const response = data.toObject(); - if (response.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE) { - this.showSavedDialog(response); - } else { - this.router.navigate(['projects', this.projectId, 'apps', response.id]); - } - }) - .catch(error => { - this.loading = false; - this.toast.showError(error); - }); + public createApp(): void { + const appOIDCCheck = this.devmode ? this.isDevOIDC : this.isStepperOIDC; + const appAPICheck = this.devmode ? this.isDevAPI : this.isStepperAPI; + + if (appOIDCCheck) { + this.requestRedirectValuesSubject$.next(); + + this.loading = true; + this.mgmtService + .CreateOIDCApp(this.oidcApp) + .then((data: Application) => { + this.loading = false; + const response = data.toObject(); + if (response.oidcConfig?.authMethodType !== OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE) { + this.showSavedDialog(response); + } else { + this.router.navigate(['projects', this.projectId, 'apps', response.id]); + } + }) + .catch(error => { + this.loading = false; + this.toast.showError(error); + }); + } else if (appAPICheck) { + this.loading = true; + this.mgmtService + .CreateAPIApplication(this.apiApp) + .then((data: Application) => { + this.loading = false; + const response = data.toObject(); + if (response.apiConfig?.authMethodType == APIAuthMethodType.APIAUTHMETHODTYPE_BASIC) { + this.showSavedDialog(response); + } else { + this.router.navigate(['projects', this.projectId, 'apps', response.id]); + } + }) + .catch(error => { + this.loading = false; + this.toast.showError(error); + }); + } } public showSavedDialog(app: Application.AsObject): void { - if (app.oidcConfig !== undefined) { + if (app.oidcConfig?.clientSecret !== undefined) { const dialogRef = this.dialog.open(AppSecretDialogComponent, { data: app.oidcConfig, }); - dialogRef.afterClosed().subscribe(result => { + dialogRef.afterClosed().subscribe(() => { + this.router.navigate(['projects', this.projectId, 'apps', app.id]); + }); + } + else if (app.apiConfig?.clientSecret !== undefined) { + const dialogRef = this.dialog.open(AppSecretDialogComponent, { + data: app.apiConfig, + }); + + dialogRef.afterClosed().subscribe(() => { this.router.navigate(['projects', this.projectId, 'apps', app.id]); }); } else { @@ -232,8 +348,8 @@ export class AppCreateComponent implements OnInit, OnDestroy { get name(): AbstractControl | null { return this.firstFormGroup.get('name'); } - get applicationType(): AbstractControl | null { - return this.firstFormGroup.get('applicationType'); + get appType(): AbstractControl | null { + return this.firstFormGroup.get('appType'); } public grantTypeChecked(type: OIDCGrantType): boolean { return this.oidcGrantTypes.filter(gt => gt.checked).map(gt => gt.type).findIndex(t => t === type) > -1; @@ -256,11 +372,30 @@ export class AppCreateComponent implements OnInit, OnDestroy { get formgrantTypesList(): AbstractControl | null { return this.form.get('grantTypesList'); } - get formapplicationType(): AbstractControl | null { - return this.form.get('applicationType'); + get formappType(): AbstractControl | null { + return this.form.get('appType'); } + // get formapplicationType(): AbstractControl | null { + // return this.form.get('applicationType'); + // } get formauthMethodType(): AbstractControl | null { return this.form.get('authMethodType'); } + + get isDevOIDC(): boolean { + return (this.formappType?.value as RadioItemAppType).createType == AppCreateType.OIDC; + } + + get isStepperOIDC(): boolean { + return (this.appType?.value as RadioItemAppType).createType == AppCreateType.OIDC; + } + + get isDevAPI(): boolean { + return (this.formappType?.value as RadioItemAppType).createType == AppCreateType.API; + } + + get isStepperAPI(): boolean { + return (this.appType?.value as RadioItemAppType).createType == AppCreateType.API; + } }; diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html index cd72ad6033..3391d3b569 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.html +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.html @@ -6,7 +6,9 @@

    {{app?.name}}

    - {{'APP.OIDC.APPTYPE'+app?.oidcConfig?.applicationType | translate}} + {{'APP.OIDC.APPTYPE.'+app?.oidcConfig?.applicationType | + translate}} + API
    @@ -54,10 +56,36 @@
    - +
    +
    + {{'APP.OIDC.INFO.CLIENTID' | translate}} +
    + {{this.app.oidcConfig?.clientId}} + +
    +
    + +
    + {{environmentV.key}} +
    + {{environmentV.value}} + +
    +
    +
    +
    @@ -70,7 +98,7 @@
    -
    +

    {{'APP.OIDC.REDIRECTSECTIONTITLE' | translate}}

    {{'APP.OIDC.REDIRECTDESCRIPTIONNATIVE' | translate}} -

    - {{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}}

    + {{'APP.OIDC.REDIRECTDESCRIPTIONWEB' | translate}} +
    - - + title="{{ 'APP.OIDC.REDIRECT' | translate }}" + [isNative]="applicationType?.value == OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE"> - +
    - + -
    + + + + +
    + +
    + + + -
    -
    @@ -120,37 +162,37 @@ - {{ 'APP.OIDC.RESPONSE' | translate }} + {{ 'APP.OIDC.RESPONSETYPE' | translate }} - {{ 'APP.OIDC.RESPONSE'+type | translate }} + {{ 'APP.OIDC.RESPONSE.'+type | translate }} - {{ 'APP.OIDC.GRANT' | translate }} + {{ 'APP.OIDC.GRANTTYPE' | translate }} - {{ 'APP.OIDC.GRANT'+grant | translate }} + {{ 'APP.OIDC.GRANT.'+grant | translate }} - {{ 'APP.OIDC.APPTYPE' | translate }} + {{ 'APP.TYPE' | translate }} - {{ 'APP.OIDC.APPTYPE'+type | translate }} + {{ 'APP.OIDC.APPTYPE.'+type | translate }} - {{ 'APP.OIDC.AUTHMETHOD' | translate }} + {{ 'APP.AUTHMETHOD' | translate }} - {{ 'APP.OIDC.AUTHMETHOD'+type | translate }} + {{ 'APP.OIDC.AUTHMETHOD.'+type | translate }} @@ -200,39 +242,14 @@
    -
    -
    -
    {{'APP.PAGES.NEXTSTEPS.TITLE' | translate}}
    -
    -
    -
    {{ 'APP.PAGES.NEXTSTEPS.0.TITLE' | translate }}
    -

    {{'APP.PAGES.NEXTSTEPS.0.DESC' | translate}}

    - - -
    -
    -
    {{ 'APP.PAGES.NEXTSTEPS.1.TITLE' | translate }}
    -

    {{'APP.PAGES.NEXTSTEPS.1.DESC' | translate}}

    - - -
    -
    -
    {{ 'APP.PAGES.NEXTSTEPS.2.TITLE' | translate }}
    -

    {{'APP.PAGES.NEXTSTEPS.2.DESC' | translate}}

    - - -
    -
    -
    +
    diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss b/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss index 894f809cca..ecb9f2599f 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.scss @@ -44,6 +44,46 @@ font-size: 14px; } +.environment-wrapper { + padding: 1rem 0; + display: flex; + flex-wrap: wrap; + + .environment { + min-width: 300px; + + .key { + font-size: 12px; + color: var(--grey); + } + .environment-row { + display: flex; + align-items: center; + overflow: hidden; + height: 30px; + + button { + transition: opacity .15s ease-in-out; + visibility: hidden; + opacity: 0; + + &[disabled] { + visibility: visible; + color: white; + opacity: 1; + } + } + + &:hover { + button { + visibility: visible; + opacity: 1; + } + } + } + } +} + .compliance .problem { font-size: 14px; } @@ -174,61 +214,3 @@ height: 1px; background-color: rgba(#8795a1, .2); } - -.next-steps { - h5 { - text-transform: uppercase; - font-size: 14px; - color: var(--grey); - } - - .row { - width: 100%; - display: flex; - overflow-x: auto; - - .step { - min-width: 220px; - max-width: 280px; - padding: 1rem; - margin: 0 .5rem; - border: 1px solid var(--grey); - border-radius: .5rem; - display: flex; - flex-direction: column; - align-items: center; - box-sizing: border-box; - flex: 1; - - h6 { - font-size: 1rem; - text-align: center; - margin: 0 0 1rem 0; - } - - p { - font-size: 14px; - text-align: center; - color: var(--grey); - } - - .fill-space { - flex: 1; - } - - button { - display: block; - margin: auto; - } - - &:first-child { - margin-left: 0; - } - - &:last-child { - margin-right: 0; - } - } - - } -} \ No newline at end of file diff --git a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts index 4cc5c5ffda..0e305606c5 100644 --- a/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts +++ b/console/src/app/pages/projects/apps/app-detail/app-detail.component.ts @@ -1,20 +1,27 @@ import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes'; import { Location } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { MatButtonToggleChange } from '@angular/material/button-toggle'; import { MatDialog } from '@angular/material/dialog'; -import { ActivatedRoute, Params, Router } from '@angular/router'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { ActivatedRoute, Params, Router, RouterLink } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { Duration } from 'google-protobuf/google/protobuf/duration_pb'; -import { Subscription } from 'rxjs'; +import { Subject, Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component'; import { ChangeType } from 'src/app/modules/changes/changes.component'; +import { CnslLinks } from 'src/app/modules/links/links.component'; import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component'; import { + APIAuthMethodType, + APIConfig, + APIConfigUpdate, Application, AppState, + ClientSecret, OIDCApplicationType, OIDCAuthMethodType, OIDCConfig, @@ -29,7 +36,7 @@ import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; import { AppSecretDialogComponent } from '../app-secret-dialog/app-secret-dialog.component'; -import { CODE_METHOD, getAuthMethodFromPartialConfig, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD, CUSTOM_METHOD } from '../authmethods'; +import { CODE_METHOD, getAuthMethodFromPartialConfig, getPartialConfigFromAuthMethod, IMPLICIT_METHOD, PKCE_METHOD, PK_JWT_METHOD, POST_METHOD, CUSTOM_METHOD, BASIC_AUTH_METHOD } from '../authmethods'; @Component({ selector: 'app-app-detail', @@ -46,11 +53,7 @@ export class AppDetailComponent implements OnInit, OnDestroy { public addOnBlur: boolean = true; public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE]; - public authMethods: RadioItemAuthType[] = [ - PKCE_METHOD, - CODE_METHOD, - POST_METHOD, - ]; + public authMethods: RadioItemAuthType[] = []; private subscription?: Subscription; public projectId: string = ''; public app!: Application.AsObject; @@ -74,6 +77,7 @@ export class AppDetailComponent implements OnInit, OnDestroy { OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + OIDCAuthMethodType.OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT, ]; public oidcTokenTypes: OIDCTokenType[] = [ @@ -83,7 +87,8 @@ export class AppDetailComponent implements OnInit, OnDestroy { public AppState: any = AppState; public appNameForm!: FormGroup; - public appForm!: FormGroup; + public oidcForm!: FormGroup; + public apiForm!: FormGroup; public redirectUrisList: string[] = []; public postLogoutRedirectUrisList: string[] = []; @@ -93,9 +98,16 @@ export class AppDetailComponent implements OnInit, OnDestroy { public OIDCApplicationType: any = OIDCApplicationType; public OIDCAuthMethodType: any = OIDCAuthMethodType; + public APIAuthMethodType: any = APIAuthMethodType; public OIDCTokenType: any = OIDCTokenType; public ChangeType: any = ChangeType; + + public requestRedirectValuesSubject$: Subject = new Subject(); + public copiedKey: any = ''; + public environmentMap: { [key: string]: string; } = {}; + public nextLinks: Array = []; + constructor( public translate: TranslateService, private route: ActivatedRoute, @@ -106,12 +118,26 @@ export class AppDetailComponent implements OnInit, OnDestroy { private mgmtService: ManagementService, private authService: GrpcAuthService, private router: Router, + private http: HttpClient, + private snackbar: MatSnackBar, ) { + this.http.get('./assets/environment.json') + .toPromise().then((env: any) => { + + this.environmentMap = { + issuer: env.issuer, + adminServiceUrl: env.adminServiceUrl, + mgmtServiceUrl: env.mgmtServiceUrl, + authServiceUrl: env.adminServiceUrl, + }; + }); + this.appNameForm = this.fb.group({ state: [{ value: '', disabled: true }, []], name: [{ value: '', disabled: true }, [Validators.required]], }); - this.appForm = this.fb.group({ + + this.oidcForm = this.fb.group({ devMode: [{ value: false, disabled: true }, []], clientId: [{ value: '', disabled: true }], responseTypesList: [{ value: [], disabled: true }], @@ -124,6 +150,10 @@ export class AppDetailComponent implements OnInit, OnDestroy { idTokenUserinfoAssertion: [{ value: false, disabled: true }], clockSkewSeconds: [{ value: 0, disabled: true }], }); + + this.apiForm = this.fb.group({ + authMethodType: [{ value: '', disabled: true }], + }); } public formatClockSkewLabel(seconds: number): string { @@ -138,8 +168,30 @@ export class AppDetailComponent implements OnInit, OnDestroy { this.subscription?.unsubscribe(); } + private initLinks(): void { + this.nextLinks = [ + { + i18nTitle: 'APP.PAGES.NEXTSTEPS.0.TITLE', + i18nDesc: 'APP.PAGES.NEXTSTEPS.0.DESC', + routerLink: ['/projects', this.projectId], + }, + { + i18nTitle: 'APP.PAGES.NEXTSTEPS.1.TITLE', + i18nDesc: 'APP.PAGES.NEXTSTEPS.1.DESC', + routerLink: ['/users', 'create'], + }, { + i18nTitle: 'APP.PAGES.NEXTSTEPS.2.TITLE', + i18nDesc: 'APP.PAGES.NEXTSTEPS.2.DESC', + href: 'https://docs.zitadel.ch' + }, + ]; + } + private async getData({ projectid, id }: Params): Promise { this.projectId = projectid; + + this.initLinks(); + this.mgmtService.GetIam().then(iam => { this.isZitadel = iam.toObject().iamProjectId === this.projectId; }); @@ -149,9 +201,22 @@ export class AppDetailComponent implements OnInit, OnDestroy { this.app = app.toObject(); this.appNameForm.patchValue(this.app); - this.getAuthMethodOptions(); if (this.app.oidcConfig) { - this.initialAuthMethod = this.authMethodFromPartialConfig(this.app.oidcConfig); + this.getAuthMethodOptions('OIDC'); + + this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: this.app.oidcConfig }); + this.currentAuthMethod = this.initialAuthMethod; + if (this.initialAuthMethod === CUSTOM_METHOD.key) { + if (!this.authMethods.includes(CUSTOM_METHOD)) { + this.authMethods.push(CUSTOM_METHOD); + } + } else { + this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD); + } + } else if (this.app.apiConfig) { + this.getAuthMethodOptions('API'); + + this.initialAuthMethod = this.authMethodFromPartialConfig({ api: this.app.apiConfig }); this.currentAuthMethod = this.initialAuthMethod; if (this.initialAuthMethod === CUSTOM_METHOD.key) { if (!this.authMethods.includes(CUSTOM_METHOD)) { @@ -164,7 +229,8 @@ export class AppDetailComponent implements OnInit, OnDestroy { if (allowed) { this.appNameForm.enable(); - this.appForm.enable(); + this.oidcForm.enable(); + this.apiForm.enable(); } if (this.app.oidcConfig?.redirectUrisList) { @@ -175,14 +241,14 @@ export class AppDetailComponent implements OnInit, OnDestroy { } if (this.app.oidcConfig?.clockSkew) { const inSecs = this.app.oidcConfig?.clockSkew.seconds + this.app.oidcConfig?.clockSkew.nanos / 100000; - this.appForm.controls['clockSkewSeconds'].setValue(inSecs); + this.oidcForm.controls['clockSkewSeconds'].setValue(inSecs); } if (this.app.oidcConfig) { - this.appForm.patchValue(this.app.oidcConfig); + this.oidcForm.patchValue(this.app.oidcConfig); } - this.appForm.valueChanges.subscribe(oidcConfig => { - this.initialAuthMethod = this.authMethodFromPartialConfig(oidcConfig); + this.oidcForm.valueChanges.subscribe((oidcConfig) => { + this.initialAuthMethod = this.authMethodFromPartialConfig({ oidc: oidcConfig }); if (this.initialAuthMethod === CUSTOM_METHOD.key) { if (!this.authMethods.includes(CUSTOM_METHOD)) { this.authMethods.push(CUSTOM_METHOD); @@ -190,6 +256,21 @@ export class AppDetailComponent implements OnInit, OnDestroy { } else { this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD); } + + this.showSaveSnack(); + }); + + this.apiForm.valueChanges.subscribe((apiConfig) => { + this.initialAuthMethod = this.authMethodFromPartialConfig({ api: apiConfig }); + if (this.initialAuthMethod === CUSTOM_METHOD.key) { + if (!this.authMethods.includes(CUSTOM_METHOD)) { + this.authMethods.push(CUSTOM_METHOD); + } + } else { + this.authMethods = this.authMethods.filter(element => element != CUSTOM_METHOD); + } + + this.showSaveSnack(); }); }).catch(error => { console.error(error); @@ -200,43 +281,68 @@ export class AppDetailComponent implements OnInit, OnDestroy { this.docs = (await this.mgmtService.GetZitadelDocs()).toObject(); } - private getAuthMethodOptions(): void { - switch (this.app.oidcConfig?.applicationType) { - case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE: - this.authMethods = [ - PKCE_METHOD, - CUSTOM_METHOD, - ]; - break; - case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB: - this.authMethods = [ - PKCE_METHOD, - CODE_METHOD, - POST_METHOD, - ]; - break; - case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT: - this.authMethods = [ - PKCE_METHOD, - IMPLICIT_METHOD, - ]; - break; + private async showSaveSnack(): Promise { + const message = await this.translate.get('APP.TOAST.CONFIGCHANGED').toPromise(); + const action = await this.translate.get('ACTIONS.SAVENOW').toPromise(); + + const snackRef = this.snackbar.open(message, action, { duration: 5000, verticalPosition: 'top' }); + snackRef.onAction().subscribe(() => { + if (this.app.oidcConfig) { + this.saveOIDCApp(); + } else if (this.app.apiConfig) { + this.saveAPIApp(); + } + }); + } + + private getAuthMethodOptions(type: string): void { + if (type == 'OIDC') { + switch (this.app.oidcConfig?.applicationType) { + case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE: + this.authMethods = [ + PKCE_METHOD, + CUSTOM_METHOD, + ]; + break; + case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB: + this.authMethods = [ + PKCE_METHOD, + CODE_METHOD, + PK_JWT_METHOD, + POST_METHOD, + ]; + break; + case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT: + this.authMethods = [ + PKCE_METHOD, + IMPLICIT_METHOD, + ]; + break; + } + } + if (type == 'API') { + this.authMethods = [ + PK_JWT_METHOD, + BASIC_AUTH_METHOD, + ]; } } - public authMethodFromPartialConfig(config: OIDCConfig.AsObject): string { + public authMethodFromPartialConfig(config: { oidc?: OIDCConfig.AsObject, api?: APIConfig.AsObject; }): string { const key = getAuthMethodFromPartialConfig(config); return key; } public setPartialConfigFromAuthMethod(authMethod: string): void { const partialConfig = getPartialConfigFromAuthMethod(authMethod); - - if (partialConfig && this.app.oidcConfig) { - this.app.oidcConfig.responseTypesList = partialConfig.responseTypesList ?? []; - this.app.oidcConfig.grantTypesList = partialConfig.grantTypesList ?? []; - this.app.oidcConfig.authMethodType = partialConfig.authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE; - this.appForm.patchValue(this.app.oidcConfig); + if (partialConfig && partialConfig.oidc && this.app.oidcConfig) { + this.app.oidcConfig.responseTypesList = (partialConfig.oidc as Partial).responseTypesList ?? []; + this.app.oidcConfig.grantTypesList = (partialConfig.oidc as Partial).grantTypesList ?? []; + this.app.oidcConfig.authMethodType = (partialConfig.oidc as Partial).authMethodType ?? OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE; + this.oidcForm.patchValue(this.app.oidcConfig); + } else if (partialConfig && partialConfig.api && this.app.apiConfig) { + this.app.apiConfig.authMethodType = (partialConfig.api as Partial).authMethodType ?? APIAuthMethodType.APIAUTHMETHODTYPE_BASIC; + this.apiAuthMethodType?.setValue(this.app.apiConfig.authMethodType); } } @@ -286,7 +392,7 @@ export class AppDetailComponent implements OnInit, OnDestroy { this.mgmtService .UpdateApplication(this.projectId, this.app.id, this.name?.value) .then(() => { - this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); + this.toast.showInfo('APP.TOAST.UPDATED', true); this.editState = false; }) .catch(error => { @@ -297,11 +403,12 @@ export class AppDetailComponent implements OnInit, OnDestroy { public saveOIDCApp(): void { + this.requestRedirectValuesSubject$.next(); if (this.appNameForm.valid) { this.app.name = this.name?.value; } - if (this.appForm.valid) { + if (this.oidcForm.valid) { if (this.app.oidcConfig) { this.app.oidcConfig.responseTypesList = this.responseTypesList?.value; this.app.oidcConfig.grantTypesList = this.grantTypesList?.value; @@ -340,7 +447,8 @@ export class AppDetailComponent implements OnInit, OnDestroy { .UpdateOIDCAppConfig(req) .then(() => { if (this.app.oidcConfig) { - this.currentAuthMethod = this.authMethodFromPartialConfig(this.app.oidcConfig); + const config = { oidc: this.app.oidcConfig }; + this.currentAuthMethod = this.authMethodFromPartialConfig(config); } this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); }) @@ -351,12 +459,52 @@ export class AppDetailComponent implements OnInit, OnDestroy { } } + public saveAPIApp(): void { + if (this.apiForm.valid && this.app.apiConfig) { + this.app.apiConfig.authMethodType = this.apiAuthMethodType?.value; + + const req = new APIConfigUpdate(); + req.setProjectId(this.projectId); + req.setApplicationId(this.app.id); + req.setAuthMethodType(this.app.apiConfig.authMethodType); + + this.mgmtService + .UpdateAPIAppConfig(req) + .then(() => { + if (this.app.apiConfig) { + const config = { api: this.app.apiConfig }; + this.currentAuthMethod = this.authMethodFromPartialConfig(config); + } + this.toast.showInfo('APP.TOAST.OIDCUPDATED', true); + }) + .catch(error => { + this.toast.showError(error); + }); + } + } + public regenerateOIDCClientSecret(): void { - this.mgmtService.RegenerateOIDCClientSecret(this.app.id, this.projectId).then((data: OIDCConfig) => { - this.toast.showInfo('APP.TOAST.OIDCCLIENTSECRETREGENERATED', true); + this.mgmtService.RegenerateOIDCClientSecret(this.app.id, this.projectId).then((data: ClientSecret) => { + this.toast.showInfo('APP.TOAST.CLIENTSECRETREGENERATED', true); this.dialog.open(AppSecretDialogComponent, { data: { - clientId: data.toObject().clientId, + // clientId: data.toObject() as ClientSecret.AsObject.clientId, + clientSecret: data.toObject().clientSecret, + }, + width: '400px', + }); + + }).catch(error => { + this.toast.showError(error); + }); + } + + public regenerateAPIClientSecret(): void { + this.mgmtService.RegenerateAPIClientSecret(this.app.id, this.projectId).then((data: ClientSecret) => { + this.toast.showInfo('APP.TOAST.CLIENTSECRETREGENERATED', true); + this.dialog.open(AppSecretDialogComponent, { + data: { + // clientId: data.toObject().clientId ?? '', clientSecret: data.toObject().clientSecret, }, width: '400px', @@ -376,46 +524,50 @@ export class AppDetailComponent implements OnInit, OnDestroy { } public get clientId(): AbstractControl | null { - return this.appForm.get('clientId'); + return this.oidcForm.get('clientId'); } public get responseTypesList(): AbstractControl | null { - return this.appForm.get('responseTypesList'); + return this.oidcForm.get('responseTypesList'); } public get grantTypesList(): AbstractControl | null { - return this.appForm.get('grantTypesList'); + return this.oidcForm.get('grantTypesList'); } public get applicationType(): AbstractControl | null { - return this.appForm.get('applicationType'); + return this.oidcForm.get('applicationType'); } public get authMethodType(): AbstractControl | null { - return this.appForm.get('authMethodType'); + return this.oidcForm.get('authMethodType'); + } + + public get apiAuthMethodType(): AbstractControl | null { + return this.apiForm.get('authMethodType'); } public get devMode(): AbstractControl | null { - return this.appForm.get('devMode'); + return this.oidcForm.get('devMode'); } public get accessTokenType(): AbstractControl | null { - return this.appForm.get('accessTokenType'); + return this.oidcForm.get('accessTokenType'); } public get idTokenRoleAssertion(): AbstractControl | null { - return this.appForm.get('idTokenRoleAssertion'); + return this.oidcForm.get('idTokenRoleAssertion'); } public get accessTokenRoleAssertion(): AbstractControl | null { - return this.appForm.get('accessTokenRoleAssertion'); + return this.oidcForm.get('accessTokenRoleAssertion'); } public get idTokenUserinfoAssertion(): AbstractControl | null { - return this.appForm.get('idTokenUserinfoAssertion'); + return this.oidcForm.get('idTokenUserinfoAssertion'); } public get clockSkewSeconds(): AbstractControl | null { - return this.appForm.get('clockSkewSeconds'); + return this.oidcForm.get('clockSkewSeconds'); } } diff --git a/console/src/app/pages/projects/apps/apps.module.ts b/console/src/app/pages/projects/apps/apps.module.ts index e1c1593c1c..2e17b5d74f 100644 --- a/console/src/app/pages/projects/apps/apps.module.ts +++ b/console/src/app/pages/projects/apps/apps.module.ts @@ -32,7 +32,9 @@ import { AppSecretDialogComponent } from './app-secret-dialog/app-secret-dialog. import { AppsRoutingModule } from './apps-routing.module'; import { A11yModule } from '@angular/cdk/a11y'; import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component'; - +import { LinksModule } from 'src/app/modules/links/links.module'; +import { RedirectPipeModule } from 'src/app/pipes/redirect-pipe/redirect-pipe.module'; +import { ClientKeysModule } from 'src/app/modules/client-keys/client-keys.module'; @NgModule({ declarations: [ AppCreateComponent, @@ -43,6 +45,8 @@ import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component'; imports: [ CommonModule, A11yModule, + RedirectPipeModule, + LinksModule, AppRadioModule, AppsRoutingModule, FormsModule, @@ -51,6 +55,7 @@ import { RedirectUrisComponent } from './redirect-uris/redirect-uris.component'; HasRoleModule, MatMenuModule, MatChipsModule, + ClientKeysModule, MatIconModule, MatSelectModule, MatButtonToggleModule, diff --git a/console/src/app/pages/projects/apps/authmethods.ts b/console/src/app/pages/projects/apps/authmethods.ts index 6d16c4ca0d..335f886dc7 100644 --- a/console/src/app/pages/projects/apps/authmethods.ts +++ b/console/src/app/pages/projects/apps/authmethods.ts @@ -1,10 +1,10 @@ import { RadioItemAuthType } from 'src/app/modules/app-radio/app-auth-method-radio/app-auth-method-radio.component'; -import { OIDCAuthMethodType, OIDCConfig, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb'; +import { APIAuthMethodType, APIConfig, OIDCAuthMethodType, OIDCConfig, OIDCGrantType, OIDCResponseType } from 'src/app/proto/generated/management_pb'; export const CODE_METHOD: RadioItemAuthType = { key: 'CODE', - titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CODE.TITLE', - descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CODE.DESCRIPTION', + titleI18nKey: 'APP.AUTHMETHODS.CODE.TITLE', + descI18nKey: 'APP.AUTHMETHODS.CODE.DESCRIPTION', disabled: false, prefix: 'CODE', background: 'rgb(89 115 128)', @@ -15,8 +15,8 @@ export const CODE_METHOD: RadioItemAuthType = { }; export const PKCE_METHOD: RadioItemAuthType = { key: 'PKCE', - titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.PKCE.TITLE', - descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.PKCE.DESCRIPTION', + titleI18nKey: 'APP.AUTHMETHODS.PKCE.TITLE', + descI18nKey: 'APP.AUTHMETHODS.PKCE.DESCRIPTION', disabled: false, prefix: 'PKCE', background: 'rgb(80 110 92)', @@ -27,11 +27,11 @@ export const PKCE_METHOD: RadioItemAuthType = { }; export const POST_METHOD: RadioItemAuthType = { key: 'POST', - titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.POST.TITLE', - descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.POST.DESCRIPTION', + titleI18nKey: 'APP.AUTHMETHODS.POST.TITLE', + descI18nKey: 'APP.AUTHMETHODS.POST.DESCRIPTION', disabled: false, prefix: 'POST', - background: '#595d80', + background: 'rgb(144 75 75)', responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE, grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE, authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, @@ -39,19 +39,34 @@ export const POST_METHOD: RadioItemAuthType = { }; export const PK_JWT_METHOD: RadioItemAuthType = { key: 'PK_JWT', - titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.ALTERNATIVE.TITLE', - descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.ALTERNATIVE.DESCRIPTION', + titleI18nKey: 'APP.AUTHMETHODS.PK_JWT.TITLE', + descI18nKey: 'APP.AUTHMETHODS.PK_JWT.DESCRIPTION', disabled: false, - prefix: 'PK_JWT', - background: '#6a506e', + prefix: 'JWT', + background: 'rgb(89, 93, 128)', + responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE, + grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE, + authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT, + apiAuthMethod: APIAuthMethodType.APIAUTHMETHODTYPE_PRIVATE_KEY_JWT, + // recommended: true, +}; +export const BASIC_AUTH_METHOD: RadioItemAuthType = { + key: 'BASIC', + titleI18nKey: 'APP.AUTHMETHODS.BASIC.TITLE', + descI18nKey: 'APP.AUTHMETHODS.BASIC.DESCRIPTION', + disabled: false, + prefix: 'BASIC', + background: 'rgb(144 75 75)', responseType: OIDCResponseType.OIDCRESPONSETYPE_CODE, grantType: OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE, authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, + apiAuthMethod: APIAuthMethodType.APIAUTHMETHODTYPE_BASIC, }; + export const IMPLICIT_METHOD: RadioItemAuthType = { key: 'IMPLICIT', - titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.IMPLICIT.TITLE', - descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.IMPLICIT.DESCRIPTION', + titleI18nKey: 'APP.AUTHMETHODS.IMPLICIT.TITLE', + descI18nKey: 'APP.AUTHMETHODS.IMPLICIT.DESCRIPTION', disabled: false, prefix: 'IMP', background: 'rgb(144 75 75)', @@ -60,51 +75,84 @@ export const IMPLICIT_METHOD: RadioItemAuthType = { authMethod: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, notRecommended: true, }; + export const CUSTOM_METHOD: RadioItemAuthType = { key: 'CUSTOM', - titleI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CUSTOM.TITLE', - descI18nKey: 'APP.OIDC.SELECTION.AUTHMETHOD.CUSTOM.DESCRIPTION', + titleI18nKey: 'APP.AUTHMETHODS.CUSTOM.TITLE', + descI18nKey: 'APP.AUTHMETHODS.CUSTOM.DESCRIPTION', disabled: false, prefix: 'CUSTOM', background: '#333', }; -export function getPartialConfigFromAuthMethod(authMethod: string): Partial | undefined { - let config: Partial; +export function getPartialConfigFromAuthMethod(authMethod: string): { + oidc?: Partial; + api?: Partial; +} | undefined { + let config: { + oidc?: Partial, + api?: Partial, + }; switch (authMethod) { case CODE_METHOD.key: config = { - responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], - grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, + oidc: { + responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], + grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, + }, }; return config; case PKCE_METHOD.key: config = { - responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], - grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + oidc: { + responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], + grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + } }; return config; case POST_METHOD.key: config = { - responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], - grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, + oidc: { + responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], + grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, + } + }; + return config; + case PK_JWT_METHOD.key: + config = { + oidc: { + responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], + grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT, + }, + api: { + authMethodType: APIAuthMethodType.APIAUTHMETHODTYPE_PRIVATE_KEY_JWT, + } + }; + return config; + case BASIC_AUTH_METHOD.key: + config = { + oidc: { + authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, + }, + api: { + authMethodType: APIAuthMethodType.APIAUTHMETHODTYPE_BASIC, + } }; return config; - // case PK_JWT_METHOD.key: - // config = { - // responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_CODE], - // grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - // authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, - // }; - // return config; case IMPLICIT_METHOD.key: config = { - responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN], - grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_IMPLICIT], - authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + oidc: { + responseTypesList: [OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN], + grantTypesList: [OIDCGrantType.OIDCGRANTTYPE_IMPLICIT], + authMethodType: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + }, + api: { + authMethodType: APIAuthMethodType.APIAUTHMETHODTYPE_PRIVATE_KEY_JWT, + } }; return config; default: @@ -112,55 +160,66 @@ export function getPartialConfigFromAuthMethod(authMethod: string): Partial | OIDCConfig.AsObject): string { - const toCheck = [config.responseTypesList, config.grantTypesList, config.authMethodType]; - const code = JSON.stringify( - [ - [OIDCResponseType.OIDCRESPONSETYPE_CODE], - [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, - ] - ); +export function getAuthMethodFromPartialConfig(config: { oidc?: Partial, api?: Partial; }): string { + if (config?.oidc) { + const toCheck = [config.oidc.responseTypesList, config.oidc.grantTypesList, config.oidc.authMethodType]; + const code = JSON.stringify( + [ + [OIDCResponseType.OIDCRESPONSETYPE_CODE], + [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, + ] + ); - const pkce = JSON.stringify( - [ - [OIDCResponseType.OIDCRESPONSETYPE_CODE], - [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, - ] - ); + const pkce = JSON.stringify( + [ + [OIDCResponseType.OIDCRESPONSETYPE_CODE], + [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + ] + ); - const post = JSON.stringify( - [ - [OIDCResponseType.OIDCRESPONSETYPE_CODE], - [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, - ] - ); + const post = JSON.stringify( + [ + [OIDCResponseType.OIDCRESPONSETYPE_CODE], + [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, + ] + ); - // const pk_jwt = JSON.stringify( - // [ - // [OIDCResponseType.OIDCRESPONSETYPE_CODE], - // [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], - // OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, - // ] - // ); + const pk_jwt = JSON.stringify( + [ + [OIDCResponseType.OIDCRESPONSETYPE_CODE], + [OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE], + OIDCAuthMethodType.OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT, + ] + ); - const implicit = JSON.stringify( - [ - [OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN], - [OIDCGrantType.OIDCGRANTTYPE_IMPLICIT], - OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, - ] - ); + const implicit = JSON.stringify( + [ + [OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN], + [OIDCGrantType.OIDCGRANTTYPE_IMPLICIT], + OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, + ] + ); - switch (JSON.stringify(toCheck)) { - case code: return CODE_METHOD.key; - case pkce: return PKCE_METHOD.key; - case post: return POST_METHOD.key; - // case pk_jwt: return PK_JWT_METHOD.key; - case implicit: return IMPLICIT_METHOD.key; - default: - return CUSTOM_METHOD.key; + switch (JSON.stringify(toCheck)) { + case code: return CODE_METHOD.key; + case pkce: return PKCE_METHOD.key; + case post: return POST_METHOD.key; + case pk_jwt: return PK_JWT_METHOD.key; + case implicit: return IMPLICIT_METHOD.key; + default: + return CUSTOM_METHOD.key; + } + } else if (config.api && config.api.authMethodType !== undefined) { + switch (config.api.authMethodType.toString()) { + case APIAuthMethodType.APIAUTHMETHODTYPE_PRIVATE_KEY_JWT.toString(): return PK_JWT_METHOD.key; + case APIAuthMethodType.APIAUTHMETHODTYPE_BASIC.toString(): return BASIC_AUTH_METHOD.key; + default: + return CUSTOM_METHOD.key; + } + } else { + return CUSTOM_METHOD.key; } } \ No newline at end of file diff --git a/console/src/app/pages/projects/apps/authtypes.ts b/console/src/app/pages/projects/apps/authtypes.ts index 9e352459e3..b047886396 100644 --- a/console/src/app/pages/projects/apps/authtypes.ts +++ b/console/src/app/pages/projects/apps/authtypes.ts @@ -1,25 +1,62 @@ import { OIDCApplicationType } from 'src/app/proto/generated/management_pb'; +// export enum AppType { +// "WEB", +// "USER_AGENT", +// "NATIVE", +// "API" +// } + +export enum AppCreateType { + API = "API", + OIDC = "OIDC" +} + +export interface RadioItemAppType { + // key: string; + createType: AppCreateType; + oidcApplicationType?: OIDCApplicationType; + titleI18nKey: string; + descI18nKey: string; + prefix: string; + background: string; +} + export const WEB_TYPE = { + // key: AppType.WEB, titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.WEB.TITLE', descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.WEB.DESCRIPTION', - type: OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, + createType: AppCreateType.OIDC, + oidcApplicationType: OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB, prefix: 'WEB', background: 'rgb(80, 110, 110)', }; export const USER_AGENT_TYPE = { + // key: AppType.USER_AGENT, titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.USERAGENT.TITLE', descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.USERAGENT.DESCRIPTION', - type: OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT, + createType: AppCreateType.OIDC, + oidcApplicationType: OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT, prefix: 'UA', background: '#6a506e', }; export const NATIVE_TYPE = { + // key: AppType.NATIVE, titleI18nKey: 'APP.OIDC.SELECTION.APPTYPE.NATIVE.TITLE', descI18nKey: 'APP.OIDC.SELECTION.APPTYPE.NATIVE.DESCRIPTION', - type: OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE, + createType: AppCreateType.OIDC, + oidcApplicationType: OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE, prefix: 'N', background: '#595d80', }; + +export const API_TYPE = { + // key: AppType.API, + titleI18nKey: 'APP.API.SELECTION.TITLE', + descI18nKey: 'APP.API.SELECTION.DESCRIPTION', + createType: AppCreateType.API, + prefix: 'API', + background: 'rgb(73,73,73)', +}; diff --git a/console/src/app/pages/projects/apps/redirect-uris/redirect-uris.component.html b/console/src/app/pages/projects/apps/redirect-uris/redirect-uris.component.html index 036853c5ff..7a4a4e7694 100644 --- a/console/src/app/pages/projects/apps/redirect-uris/redirect-uris.component.html +++ b/console/src/app/pages/projects/apps/redirect-uris/redirect-uris.component.html @@ -15,8 +15,7 @@ {{uri}} - - +