diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 49c19ce..2adfaf0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,7 @@ stages: build: stage: build - image: node:12.2 + image: node:14.16 before_script: - mkdir -p build script: diff --git a/Dockerfile b/Dockerfile index 5b3050f..005f421 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ # along with VILLASweb. If not, see . # ****************************************************************************** -FROM node:12.2 AS builder +FROM node:14.16 AS builder # Create app directory RUN mkdir -p /usr/src/app diff --git a/package-lock.json b/package-lock.json index 01667d7..e2b07e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -82,9 +82,9 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz", - "integrity": "sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.8.tgz", + "integrity": "sha512-pBljUGC1y3xKLn1nrx2eAhurLMA8OqBtBP/JwG4U8skN7kf8/aqwwxpV1N6T0e7r6+7uNitIa/fUxPFagSXp3A==", "requires": { "@babel/compat-data": "^7.13.8", "@babel/helper-validator-option": "^7.12.17", @@ -100,9 +100,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.10.tgz", - "integrity": "sha512-YV7r2YxdTUaw84EwNkyrRke/TJHR/UXGiyvACRqvdVJ2/syV2rQuJNnaRLSuYiop8cMRXOgseTGoJCWX0q2fFg==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.8.tgz", + "integrity": "sha512-qioaRrKHQbn4hkRKDHbnuQ6kAxmmOF+kzKGnIfxPK4j2rckSJCpKzr/SSTlohSCiE3uAQpNDJ9FIh4baeE8W+w==", "requires": { "@babel/helper-function-name": "^7.12.13", "@babel/helper-member-expression-to-functions": "^7.13.0", @@ -298,9 +298,9 @@ } }, "@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz", + "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==", "requires": { "@babel/template": "^7.12.13", "@babel/traverse": "^7.13.0", @@ -308,9 +308,9 @@ } }, "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.8.tgz", + "integrity": "sha512-4vrIhfJyfNf+lCtXC2ck1rKSzDwciqF7IWFhXXrSOUC2O5DrVp+w4c6ed4AllTxhTkUP5x2tYj41VaxdVMMRDw==", "requires": { "@babel/helper-validator-identifier": "^7.12.11", "chalk": "^2.0.0", @@ -318,9 +318,9 @@ } }, "@babel/parser": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.10.tgz", - "integrity": "sha512-0s7Mlrw9uTWkYua7xWr99Wpk2bnGa0ANleKfksYAES8LpWH4gW1OUr42vqKNf0us5UQNfru2wPqMqRITzq/SIQ==" + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.9.tgz", + "integrity": "sha512-nEUfRiARCcaVo3ny3ZQjURjHQZUo/JkEw7rLlSZy/psWGnvwXFtPcr6jb7Yb41DVW5LTe6KRq9LGleRNsg1Frw==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.13.8", @@ -814,11 +814,11 @@ } }, "@babel/plugin-transform-react-constant-elements": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.13.10.tgz", - "integrity": "sha512-E+aCW9j7mLq01tOuGV08YzLBt+vSyr4bOPT75B6WrAlrUfmOYOZ/yWk847EH0dv0xXiCihWLEmlX//O30YhpIw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.12.13.tgz", + "integrity": "sha512-qmzKVTn46Upvtxv8LQoQ8mTCdUC83AOVQIQm57e9oekLT5cmK9GOMOfcWhe8jMNx4UJXn/UDhVZ/7lGofVNeDQ==", "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-react-display-name": { @@ -970,12 +970,12 @@ } }, "@babel/preset-env": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.10.tgz", - "integrity": "sha512-nOsTScuoRghRtUsRr/c69d042ysfPHcu+KOB4A9aAO9eJYqrkat+LF8G1yp1HD18QiwixT2CisZTr/0b3YZPXQ==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.9.tgz", + "integrity": "sha512-mcsHUlh2rIhViqMG823JpscLMesRt3QbMsv1+jhopXEb3W2wXvQ9QoiOlZI9ZbR3XqPtaFpZwEZKYqGJnGMZTQ==", "requires": { "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.10", + "@babel/helper-compilation-targets": "^7.13.8", "@babel/helper-plugin-utils": "^7.13.0", "@babel/helper-validator-option": "^7.12.17", "@babel/plugin-proposal-async-generator-functions": "^7.13.8", @@ -1238,24 +1238,24 @@ } }, "@fortawesome/fontawesome-common-types": { - "version": "0.2.34", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.34.tgz", - "integrity": "sha512-XcIn3iYbTEzGIxD0/dY5+4f019jIcEIWBiHc3KrmK/ROahwxmZ/s+tdj97p/5K0klz4zZUiMfUlYP0ajhSJjmA==" + "version": "0.2.35", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz", + "integrity": "sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw==" }, "@fortawesome/fontawesome-svg-core": { - "version": "1.2.34", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.34.tgz", - "integrity": "sha512-0KNN0nc5eIzaJxlv43QcDmTkDY1CqeN6J7OCGSs+fwGPdtv0yOQqRjieopBCmw+yd7uD3N2HeNL3Zm5isDleLg==", + "version": "1.2.35", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz", + "integrity": "sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg==", "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.34" + "@fortawesome/fontawesome-common-types": "^0.2.35" } }, "@fortawesome/free-solid-svg-icons": { - "version": "5.15.2", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.2.tgz", - "integrity": "sha512-ZfCU+QjaFsdNZmOGmfqEWhzI3JOe37x5dF4kz9GeXvKn/sTxhqMtZ7mh3lBf76SvcYY5/GKFuyG7p1r4iWMQqw==", + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz", + "integrity": "sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q==", "requires": { - "@fortawesome/fontawesome-common-types": "^0.2.34" + "@fortawesome/fontawesome-common-types": "^0.2.35" } }, "@fortawesome/react-fontawesome": { @@ -2253,9 +2253,9 @@ "integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw==" }, "@types/eslint": { - "version": "7.2.7", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.7.tgz", - "integrity": "sha512-EHXbc1z2GoQRqHaAT7+grxlTJ3WE2YNeD6jlpPoRc83cCoThRY+NUWjCUZaYmk51OICkPXn2hhphcWcWXgNW0Q==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.6.tgz", + "integrity": "sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==", "requires": { "@types/estree": "*", "@types/json-schema": "*" @@ -2291,15 +2291,6 @@ "@types/unist": "*" } }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "@types/html-minifier-terser": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", @@ -2377,12 +2368,13 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "@types/react": { - "version": "16.9.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.17.tgz", - "integrity": "sha512-UP27In4fp4sWF5JgyV6pwVPAQM83Fj76JOcg02X5BZcpSu5Wx+fP9RMqc2v0ssBoQIFvD5JdKY41gjJJKmw6Bg==", + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", + "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", "requires": { "@types/prop-types": "*", - "csstype": "^2.2.0" + "@types/scheduler": "*", + "csstype": "^3.0.2" } }, "@types/react-transition-group": { @@ -2422,9 +2414,9 @@ "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==" }, "@types/uglify-js": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", - "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.12.0.tgz", + "integrity": "sha512-sYAF+CF9XZ5cvEBkI7RtrG9g2GtMBkviTnBxYYyq+8BWvO4QtXfwwR6a2LFwCi4evMKZfpv6U43ViYvv17Wz3Q==", "requires": { "source-map": "^0.6.1" } @@ -2483,12 +2475,12 @@ "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" }, "@typescript-eslint/eslint-plugin": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz", - "integrity": "sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.16.1.tgz", + "integrity": "sha512-SK777klBdlkUZpZLC1mPvyOWk9yAFCWmug13eAjVQ4/Q1LATE/NbcQL1xDHkptQkZOLnPmLUA1Y54m8dqYwnoQ==", "requires": { - "@typescript-eslint/experimental-utils": "4.17.0", - "@typescript-eslint/scope-manager": "4.17.0", + "@typescript-eslint/experimental-utils": "4.16.1", + "@typescript-eslint/scope-manager": "4.16.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", @@ -2508,50 +2500,50 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz", - "integrity": "sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.16.1.tgz", + "integrity": "sha512-0Hm3LSlMYFK17jO4iY3un1Ve9x1zLNn4EM50Lia+0EV99NdbK+cn0er7HC7IvBA23mBg3P+8dUkMXy4leL33UQ==", "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.17.0", - "@typescript-eslint/types": "4.17.0", - "@typescript-eslint/typescript-estree": "4.17.0", + "@typescript-eslint/scope-manager": "4.16.1", + "@typescript-eslint/types": "4.16.1", + "@typescript-eslint/typescript-estree": "4.16.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.17.0.tgz", - "integrity": "sha512-KYdksiZQ0N1t+6qpnl6JeK9ycCFprS9xBAiIrw4gSphqONt8wydBw4BXJi3C11ywZmyHulvMaLjWsxDjUSDwAw==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.16.1.tgz", + "integrity": "sha512-/c0LEZcDL5y8RyI1zLcmZMvJrsR6SM1uetskFkoh3dvqDKVXPsXI+wFB/CbVw7WkEyyTKobC1mUNp/5y6gRvXg==", "requires": { - "@typescript-eslint/scope-manager": "4.17.0", - "@typescript-eslint/types": "4.17.0", - "@typescript-eslint/typescript-estree": "4.17.0", + "@typescript-eslint/scope-manager": "4.16.1", + "@typescript-eslint/types": "4.16.1", + "@typescript-eslint/typescript-estree": "4.16.1", "debug": "^4.1.1" } }, "@typescript-eslint/scope-manager": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.17.0.tgz", - "integrity": "sha512-OJ+CeTliuW+UZ9qgULrnGpPQ1bhrZNFpfT/Bc0pzNeyZwMik7/ykJ0JHnQ7krHanFN9wcnPK89pwn84cRUmYjw==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.16.1.tgz", + "integrity": "sha512-6IlZv9JaurqV0jkEg923cV49aAn8V6+1H1DRfhRcvZUrptQ+UtSKHb5kwTayzOYTJJ/RsYZdcvhOEKiBLyc0Cw==", "requires": { - "@typescript-eslint/types": "4.17.0", - "@typescript-eslint/visitor-keys": "4.17.0" + "@typescript-eslint/types": "4.16.1", + "@typescript-eslint/visitor-keys": "4.16.1" } }, "@typescript-eslint/types": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.17.0.tgz", - "integrity": "sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g==" + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.16.1.tgz", + "integrity": "sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA==" }, "@typescript-eslint/typescript-estree": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.17.0.tgz", - "integrity": "sha512-lRhSFIZKUEPPWpWfwuZBH9trYIEJSI0vYsrxbvVvNyIUDoKWaklOAelsSkeh3E2VBSZiNe9BZ4E5tYBZbUczVQ==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.16.1.tgz", + "integrity": "sha512-m8I/DKHa8YbeHt31T+UGd/l8Kwr0XCTCZL3H4HMvvLCT7HU9V7yYdinTOv1gf/zfqNeDcCgaFH2BMsS8x6NvJg==", "requires": { - "@typescript-eslint/types": "4.17.0", - "@typescript-eslint/visitor-keys": "4.17.0", + "@typescript-eslint/types": "4.16.1", + "@typescript-eslint/visitor-keys": "4.16.1", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", @@ -2570,11 +2562,11 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.17.0.tgz", - "integrity": "sha512-WfuMN8mm5SSqXuAr9NM+fItJ0SVVphobWYkWOwQ1odsfC014Vdxk/92t4JwS1Q6fCA/ABfCKpa3AVtpUKTNKGQ==", + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.16.1.tgz", + "integrity": "sha512-s/aIP1XcMkEqCNcPQtl60ogUYjSM8FU2mq1O7y5cFf3Xcob1z1iXWNB6cC43Op+NGRTFgGolri6s8z/efA9i1w==", "requires": { - "@typescript-eslint/types": "4.17.0", + "@typescript-eslint/types": "4.16.1", "eslint-visitor-keys": "^2.0.0" } }, @@ -2907,9 +2899,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", + "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -3108,9 +3100,9 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, "autolinker": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.2.tgz", - "integrity": "sha512-VO66nXUCZFxTq7fVHAaiAkZNXRQ1l3IFi6D5P7DLoyIEAn2E8g7TWbyEgLlz1uW74LfWmu1A17IPWuPQyGuNVg==", + "version": "3.14.3", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.3.tgz", + "integrity": "sha512-t81i2bCpS+s+5FIhatoww9DmpjhbdiimuU9ATEuLxtZMQ7jLv9fyFn7SWNG8IkEfD4AmYyirL1ss9k1aqVWRvg==", "requires": { "tslib": "^1.9.3" }, @@ -3147,9 +3139,9 @@ "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" }, "axe-core": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.3.tgz", - "integrity": "sha512-vwPpH4Aj4122EW38mxO/fxhGKtwWTMLDIJfZ1He0Edbtjcfna/R3YB67yVhezUMzqc3Jr3+Ii50KRntlENL4xQ==" + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.2.tgz", + "integrity": "sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==" }, "axobject-query": { "version": "2.2.0", @@ -3700,9 +3692,9 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", "optional": true }, "bluebird": { @@ -4027,24 +4019,6 @@ "requires": { "glob": "^7.1.3" } - }, - "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, @@ -4108,6 +4082,13 @@ "requires": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } } }, "camelcase": { @@ -4127,9 +4108,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001199", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001199.tgz", - "integrity": "sha512-ifbK2eChUCFUwGhlEzIoVwzFt1+iriSjyKKFYNfv6hN34483wyWpLLavYQXhnR036LhkdUYaSDpHg1El++VgHQ==" + "version": "1.0.30001196", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001196.tgz", + "integrity": "sha512-CPvObjD3ovWrNBaXlAIGWmg2gQQuJ5YhuciUOjPRox6hIQttu8O+b51dx6VIpIY9ESd2d0Vac1RKpICdG4rGUg==" }, "capture-exit": { "version": "2.0.0", @@ -4185,9 +4166,9 @@ "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==" }, "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", "optional": true, "requires": { "anymatch": "~3.1.1", @@ -4261,9 +4242,9 @@ } }, "classnames": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" }, "clean-css": { "version": "4.2.3", @@ -4321,6 +4302,11 @@ } } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -5008,9 +4994,9 @@ } }, "csstype": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.8.tgz", - "integrity": "sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" }, "cyclist": { "version": "1.0.1", @@ -5027,9 +5013,9 @@ } }, "d3": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-6.6.0.tgz", - "integrity": "sha512-fWyMfZDSOLksXeYuiHM/uHap7pKgypUnOGY8jiTfmmAWH1HM6ErPtnHiKEdqs7DtZqbombUgaKwq3B5Pjm7GOQ==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-6.7.0.tgz", + "integrity": "sha512-hNHRhe+yCDLUG6Q2LwvR/WdNFPOJQ5VWqsJcwIYVeI401+d2/rrCjxSXkiAdIlpx7/73eApFB4Olsmh3YN7a6g==", "requires": { "d3-array": "2", "d3-axis": "2", @@ -5077,16 +5063,19 @@ } }, "d3-time": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.0.0.tgz", - "integrity": "sha512-2mvhstTFcMvwStWd9Tj3e6CEqtOivtD8AUiHT8ido/xmzrI9ijrUUihZ6nHuf/vsScRBonagOdj0Vv+SEL5G3Q==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "requires": { + "d3-array": "2" + } } } }, "d3-array": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.0.tgz", - "integrity": "sha512-T6H/qNldyD/1OlRkJbonb3u3MPhNwju8OPxYv0YSjDb/B2RUeeBEHzIpNrYiinwpmz8+am+puMrpcrDWgY9wRg==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", "requires": { "internmap": "^1.0.0" } @@ -5238,15 +5227,25 @@ "integrity": "sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw==" }, "d3-scale": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz", - "integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.3.0.tgz", + "integrity": "sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==", "requires": { "d3-array": "^2.3.0", "d3-format": "1 - 2", "d3-interpolate": "1.2.0 - 2", - "d3-time": "1 - 2", + "d3-time": "^2.1.1", "d3-time-format": "2 - 3" + }, + "dependencies": { + "d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "requires": { + "d3-array": "2" + } + } } }, "d3-scale-chromatic": { @@ -5593,6 +5592,16 @@ "path-type": "^4.0.0" } }, + "dnd-core": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-12.0.1.tgz", + "integrity": "sha512-KzfKXQM9t9uSBO7DFmrILVgXUCShpY3/MbnLPF9/wg1Wcvq2KblbeT72GhjcrplS9cz0DFXilE1NXy43n8plag==", + "requires": { + "@react-dnd/asap": "^4.0.0", + "@react-dnd/invariant": "^2.0.0", + "redux": "^4.0.5" + } + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -5653,11 +5662,6 @@ "regenerator-runtime": "^0.13.4" } }, - "csstype": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", - "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" - }, "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", @@ -5715,9 +5719,9 @@ } }, "dompurify": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.6.tgz", - "integrity": "sha512-7b7ZArhhH0SP6W2R9cqK6RjaU82FZ2UPM7RO8qN1b1wyvC/NY1FNWcX1Pu00fFOAnzEORtwXe4bPaClg6pUybQ==" + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.2.7.tgz", + "integrity": "sha512-jdtDffdGNY+C76jvodNTu9jt5yYj59vuTUyx+wXdzcSwAGTYZDAQkQ7Iwx9zcGrA4ixC1syU4H3RZROqRxokxg==" }, "domutils": { "version": "1.7.0", @@ -5735,6 +5739,13 @@ "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } } }, "dot-prop": { @@ -5799,9 +5810,9 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" }, "electron-to-chromium": { - "version": "1.3.687", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.687.tgz", - "integrity": "sha512-IpzksdQNl3wdgkzf7dnA7/v10w0Utf1dF2L+B4+gKrloBrxCut+au+kky3PYvle3RMdSxZP+UiCZtLbcYRxSNQ==" + "version": "1.3.680", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.680.tgz", + "integrity": "sha512-XBACJT9RdpdWtoMXQPR8Be3ZtmizWWbxfw8cY2b5feUwiDO3FUl8qo4W2jXoq/WnnA3xBRqafu1XbpczqyUvlA==" }, "elliptic": { "version": "6.5.4", @@ -5849,14 +5860,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, - "encoding": { - "version": "0.1.12", - "resolved": false, - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "~0.4.13" - } - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6416,9 +6419,9 @@ } }, "eslint-plugin-jest": { - "version": "24.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.2.1.tgz", - "integrity": "sha512-s24ve8WUu3DLVidvlSzaqlOpTZre9lTkZTAO+a7X0WMtj8HraWTiTEkW3pbDT1xVxqEHMWSv+Kx7MyqR50nhBw==", + "version": "24.1.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.1.5.tgz", + "integrity": "sha512-FIP3lwC8EzEG+rOs1y96cOJmMVpdFNreoDJv29B5vIupVssRi8zrSY3QadogT0K3h1Y8TMxJ6ZSAzYUmFCp2hg==", "requires": { "@typescript-eslint/experimental-utils": "^4.0.1" } @@ -6442,9 +6445,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", + "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -7094,32 +7097,25 @@ } }, "fbemitter": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-2.1.1.tgz", - "integrity": "sha1-Uj4U/a9SSIBbsC9i78M75wP1GGU=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz", + "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==", "requires": { - "fbjs": "^0.8.4" + "fbjs": "^3.0.0" } }, "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz", + "integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==", "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", "loose-envify": "^1.0.0", "object-assign": "^4.1.0", "promise": "^7.1.1", "setimmediate": "^1.0.5", "ua-parser-js": "^0.7.18" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - } } }, "fbjs-css-vars": { @@ -7127,14 +7123,6 @@ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" }, - "fibers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fibers/-/fibers-5.0.0.tgz", - "integrity": "sha512-UpGv/YAZp7mhKHxDvC1tColrroGRX90sSvh8RMZV9leo+e5+EkRVgCEZPlmXeo3BUNQTZxUaVdLskq1Q2FyCPg==", - "requires": { - "detect-libc": "^1.0.3" - } - }, "figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -7297,12 +7285,12 @@ } }, "flux": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/flux/-/flux-3.1.3.tgz", - "integrity": "sha1-0jvtUVp5oi2TOrU6tK2hnQWy8Io=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.1.tgz", + "integrity": "sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ==", "requires": { - "fbemitter": "^2.0.0", - "fbjs": "^0.8.0" + "fbemitter": "^3.0.0", + "fbjs": "^3.0.0" } }, "follow-redirects": { @@ -7489,6 +7477,14 @@ "universalify": "^2.0.0" } }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, "fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", @@ -7841,9 +7837,9 @@ "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, "highlight.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.6.0.tgz", - "integrity": "sha512-8mlRcn5vk/r4+QcqerapwBYTe+iPL5ih6xrNylxrnBdHQiijDETfXX7VIxC3UiCRiINBJfANBAsPzAvRQj8RpQ==" + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.2.tgz", + "integrity": "sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==" }, "history": { "version": "4.10.1", @@ -8742,15 +8738,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, "isomorphic-form-data": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isomorphic-form-data/-/isomorphic-form-data-2.0.0.tgz", @@ -10613,51 +10600,6 @@ "whatwg-url": "^8.0.0", "ws": "^7.4.4", "xml-name-validator": "^3.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.0.tgz", - "integrity": "sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA==" - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - } } }, "jsesc": { @@ -10791,14 +10733,6 @@ "safe-buffer": "^5.0.1" } }, - "keygrip": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", - "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", - "requires": { - "tsscmp": "1.0.6" - } - }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -11037,15 +10971,22 @@ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "requires": { "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } } }, "lowlight": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.19.0.tgz", - "integrity": "sha512-NIskvQ1d1ovKyUytkMpT8+8Bhq3Ub54os1Xp4RAC9uNbXH1YVRf5NERq7JNzapEe5BzUc1Cj4F0I+eLBBFj6hA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", "requires": { "fault": "^1.0.0", - "highlight.js": "~10.6.0" + "highlight.js": "~10.7.0" } }, "lru-cache": { @@ -11484,6 +11425,26 @@ "object-assign": "^4.1.1", "prop-types": "^15.6.2" } + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } } } }, @@ -11493,11 +11454,6 @@ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "optional": true }, - "nanoid": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.21.tgz", - "integrity": "sha512-A6oZraK4DJkAOICstsGH98dvycPr/4GGDH7ZWKmMdd3vGcOurZ6JmWFUt0DA5bzrrn2FrUjmv6mFNWvv8jpppA==" - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -11556,15 +11512,13 @@ "requires": { "lower-case": "^2.0.2", "tslib": "^2.0.3" - } - }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } } }, "node-forge": { @@ -11620,9 +11574,9 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" }, "node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", + "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", "optional": true, "requires": { "growly": "^1.3.0", @@ -12018,6 +11972,13 @@ "requires": { "dot-case": "^3.0.4", "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } } }, "parent-module": { @@ -12081,6 +12042,13 @@ "requires": { "no-case": "^3.0.4", "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } } }, "pascalcase": { @@ -13202,10 +13170,15 @@ "postcss": "^8.1.0" }, "dependencies": { + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==" + }, "postcss": { - "version": "8.2.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.8.tgz", - "integrity": "sha512-1F0Xb2T21xET7oQV9eKuctbM9S7BC0fetoHCc4H13z0PT6haiRLP4T0ZY4XWh7iLP0usgqykT6p9B2RtOf4FPw==", + "version": "8.2.7", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.7.tgz", + "integrity": "sha512-DsVLH3xJzut+VT+rYr0mtvOtpTjSyqDwPf5EZWXcb0uAKfitGpTY9Ec+afi2+TgdN8rWS9Cs88UDYehKo/RvOw==", "requires": { "colorette": "^1.2.2", "nanoid": "^3.1.20", @@ -13645,9 +13618,9 @@ } }, "rc-slider": { - "version": "9.7.1", - "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.7.1.tgz", - "integrity": "sha512-r9r0dpFA3PEvxBhIfVi1lVzxuSogWxeY+tGvi2AqMM1rPgaOXQ7WbtT+9kVFkJ9K8TntA/vYPgiCCKfN29KTkw==", + "version": "9.7.2", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.7.2.tgz", + "integrity": "sha512-mVaLRpDo6otasBs6yVnG02ykI3K6hIrLTNfT5eyaqduFv95UODI9PDS6fWuVVehVpdS4ENgOSwsTjrPVun+k9g==", "requires": { "@babel/runtime": "^7.10.1", "classnames": "^2.2.5", @@ -13696,9 +13669,9 @@ } }, "rc-trigger": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.3.tgz", - "integrity": "sha512-6Fokao07HUbqKIDkDRFEM0AGZvsvK0Fbp8A/KFgl1ngaqfO1nY037cISCG1Jm5fxImVsXp9awdkP7Vu5cxjjog==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.5.tgz", + "integrity": "sha512-RlF5RpWqK+JeiFeQVOzwjLFzpNe2FowoXc/42azz+20wr/bYF1Q/MwprUK+3+vs/oFhLC0ht3/NlrslAo/OoWA==", "requires": { "@babel/runtime": "^7.11.2", "classnames": "^2.2.6", @@ -13723,9 +13696,9 @@ } }, "rc-util": { - "version": "5.8.1", - "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.8.1.tgz", - "integrity": "sha512-kXV/QjL+azh3AxMk68gm8+nltVoL6bjeJJULAZLRCLus2Fhvo/aaMZokxYov/E0dbfjo31I78pF4yVljqQB7bA==", + "version": "5.9.8", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.9.8.tgz", + "integrity": "sha512-typLSHYGf5irvGLYQshs0Ra3aze086h0FhzsAkyirMunYZ7b3Te8gKa5PVaanoHaZa9sS6qx98BxgysoRP+6Tw==", "requires": { "@babel/runtime": "^7.12.5", "react-is": "^16.12.0", @@ -13761,13 +13734,12 @@ } }, "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" } }, "react-app-polyfill": { @@ -13800,11 +13772,6 @@ "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" - }, - "whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" } } }, @@ -13852,21 +13819,6 @@ "regenerator-runtime": "^0.13.4" } }, - "@types/react": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", - "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "csstype": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", - "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" - }, "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", @@ -13894,12 +13846,11 @@ } }, "react-contexify": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/react-contexify/-/react-contexify-4.1.1.tgz", - "integrity": "sha512-WJeRI4ohHEOmNiH0xb62a/eV+5ae168FB7H6pfbeEVJkf0UN7D5H99l6b89poc2LHKN1gOimFjREyY8quGVsXA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-contexify/-/react-contexify-5.0.0.tgz", + "integrity": "sha512-2FIp7lxJ6dtfGr8EZ4uVV5p5TQjd0n2h/JU7PrejNIMiCeZWvSVPFh4lj1ZvjXosglBvP7q5JQQ8yUCdSaMSaw==", "requires": { - "classnames": "^2.2.6", - "prop-types": "^15.6.2" + "clsx": "^1.1.1" } }, "react-copy-to-clipboard": { @@ -14037,57 +13988,52 @@ "integrity": "sha512-zvU6iouW+SWwHTyThwxGICjJYCMZFk/6r/+jmOdC7ntQoPlS/Pqb81MkxaMf2bHTSq9TN3K3zX2/ayMW/jCtyA==" }, "react-dnd": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-10.0.2.tgz", - "integrity": "sha512-SC2Ymvntynhoqtf5zaFhZscm9xenCoMofilxPdlwUlaelAzmbl9fw82C4ZJ//+lNm3kWAKXjGDZg2/aWjKEAtg==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-13.1.1.tgz", + "integrity": "sha512-oxQW8846omV1l3Pm2zY/atvNxryx+blW1rxnSmoGvFMgmxXpOHulaXrlXgxRH+OLRvLt2cfVTSxZ4ykbzBypaw==", "requires": { + "@react-dnd/invariant": "^2.0.0", "@react-dnd/shallowequal": "^2.0.0", - "@types/hoist-non-react-statics": "^3.3.1", - "dnd-core": "^10.0.2", - "hoist-non-react-statics": "^3.3.0" + "dnd-core": "12.0.1", + "hoist-non-react-statics": "^3.3.2" }, "dependencies": { "dnd-core": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-10.0.2.tgz", - "integrity": "sha512-PrxEjxF0+6Y1n1n1Z9hSWZ1tvnDXv9syL+BccV1r1RC08uWNsyetf8AnWmUF3NgYPwy0HKQJwTqGkZK+1NlaFA==", + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-12.0.1.tgz", + "integrity": "sha512-KzfKXQM9t9uSBO7DFmrILVgXUCShpY3/MbnLPF9/wg1Wcvq2KblbeT72GhjcrplS9cz0DFXilE1NXy43n8plag==", "requires": { "@react-dnd/asap": "^4.0.0", "@react-dnd/invariant": "^2.0.0", - "redux": "^4.0.4" + "redux": "^4.0.5" + } + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" } } } }, "react-dnd-html5-backend": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-10.0.2.tgz", - "integrity": "sha512-ny17gUdInZ6PIGXdzfwPhoztRdNVVvjoJMdG80hkDBamJBeUPuNF2Wv4D3uoQJLjXssX1+i9PhBqc7EpogClwQ==", + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-12.1.1.tgz", + "integrity": "sha512-cQZgfuSGQEwHdvdoPtfUOvcrS8rye/V0hU046LjY/BLSgcrdjtQVviE2d/81QQaeJpvK00JizctsZqVY7IvHgA==", "requires": { - "dnd-core": "^10.0.2" - }, - "dependencies": { - "dnd-core": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-10.0.2.tgz", - "integrity": "sha512-PrxEjxF0+6Y1n1n1Z9hSWZ1tvnDXv9syL+BccV1r1RC08uWNsyetf8AnWmUF3NgYPwy0HKQJwTqGkZK+1NlaFA==", - "requires": { - "@react-dnd/asap": "^4.0.0", - "@react-dnd/invariant": "^2.0.0", - "redux": "^4.0.4" - } - } + "dnd-core": "12.0.1" } }, "react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.20.2" } }, "react-draggable": { @@ -14109,6 +14055,14 @@ "react-display-name": "^0.2.0" } }, + "react-grid-system": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/react-grid-system/-/react-grid-system-7.1.2.tgz", + "integrity": "sha512-5XKVkevZWDITlpivmK8iQcmdfj7cuIzPlcejOmhRK9FGdNsFsRHXO2H7zaKfssJ2CymQXOTvU0ZN8TX9BPBr+g==", + "requires": { + "prop-types": "^15.7.2" + } + }, "react-immutable-proptypes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz", @@ -14268,6 +14222,13 @@ "re-resizable": "6.9.0", "react-draggable": "4.4.3", "tslib": "2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } } }, "react-router": { @@ -14617,9 +14578,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", + "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -14748,6 +14709,44 @@ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, "request-promise-core": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", @@ -15248,6 +15247,11 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, "schema-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", @@ -15257,14 +15261,6 @@ "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "requires": { - "lru-cache": "^6.0.0" - } } } }, @@ -15282,9 +15278,9 @@ } }, "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -16183,6 +16179,11 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, "style-loader": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", @@ -16322,9 +16323,9 @@ } }, "swagger-client": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.13.1.tgz", - "integrity": "sha512-Hmy4+wVVa3kveWzC7PIeUwiAY5qcYbm4XlC4uZ7e5kAePfB2cprXImiqrZHIzL+ndU0YTN7I+9w/ZayTisn3Jg==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/swagger-client/-/swagger-client-3.13.2.tgz", + "integrity": "sha512-kamtyXtmbZiA2C5YTVqJYgoPJgzqtM5RbeP23Rt/YPYjMArTKZ2fjx1UTsI0aSbws0GluU5pVHiGp8YMciSUfw==", "requires": { "@babel/runtime-corejs3": "^7.11.2", "btoa": "^1.2.1", @@ -16357,26 +16358,29 @@ "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" }, "qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", + "requires": { + "side-channel": "^1.0.4" + } } } }, "swagger-ui-react": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-3.45.0.tgz", - "integrity": "sha512-wCoZEWfhg6/6u0sY2Kks1zDua2aMQnSMnS10/N/40G4h2SGr6Qfqex5ca5uaJvprpLLIPUv4BcRHs++ZTxjK4A==", + "version": "3.47.1", + "resolved": "https://registry.npmjs.org/swagger-ui-react/-/swagger-ui-react-3.47.1.tgz", + "integrity": "sha512-KPfhRE3kJnN9/yKrPIvKNrZYzGxSLQOEc0gVUlYXrMh6iQ5rR/fW8s9xXCV0ivOOvhvr09LQ5H3ZjwAIbvUHoA==", "requires": { - "@babel/runtime-corejs3": "^7.13.9", + "@babel/runtime-corejs3": "^7.13.10", "@braintree/sanitize-url": "^5.0.0", "@kyleshockey/object-assign-deep": "^0.4.2", "@kyleshockey/xml": "^1.0.2", "base64-js": "^1.5.1", - "classnames": "^2.2.6", + "classnames": "^2.3.1", "css.escape": "1.5.1", "deep-extend": "0.6.0", - "dompurify": "^2.2.6", + "dompurify": "^2.2.7", "ieee754": "^1.2.1", "immutable": "^3.x.x", "js-file-download": "^0.4.12", @@ -16399,12 +16403,21 @@ "reselect": "^4.0.0", "serialize-error": "^2.1.0", "sha.js": "^2.4.11", - "swagger-client": "^3.13.1", + "swagger-client": "^3.13.2", "url-parse": "^1.5.1", "xml-but-prettier": "^1.0.1", "zenscroll": "^4.0.2" }, "dependencies": { + "@babel/runtime-corejs3": { + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.10.tgz", + "integrity": "sha512-x/XYVQ1h684pp1mJwOV4CyvqZXqbc8CMsMGUnAbuc82ZCdv1U63w5RSUzgDSXQHG5Rps/kiksH6g2D5BuaKyXg==", + "requires": { + "core-js-pure": "^3.0.0", + "regenerator-runtime": "^0.13.4" + } + }, "redux": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", @@ -16415,6 +16428,20 @@ "loose-envify": "^1.1.0", "symbol-observable": "^1.0.3" } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } } } }, @@ -16440,9 +16467,9 @@ }, "dependencies": { "ajv": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.2.1.tgz", - "integrity": "sha512-+nu0HDv7kNSOua9apAVc979qd932rrZeb3WOvoiD31A/p1mIE5/9bN2027pE2rOPYEdS3UHzsvof4hY+lM9/WQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz", + "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -16467,6 +16494,26 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, + "tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, "temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", @@ -16785,9 +16832,9 @@ } }, "transformation-matrix": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.7.0.tgz", - "integrity": "sha512-Q+0wR7xPOW9XOy8+S0+N2bPOQpXlDVPiFGPZKncgUIlcvlOnp6XtKF+TAgo0Ek9pRQAOEWZx2f506XnwWU/rwA==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.6.0.tgz", + "integrity": "sha512-2VxseZ2BgdOkiEnD+o8ZnRheTXrZ5fDrxSZWELPkYDR0zmFI5NzB5qJtBfgaWl8bjeiMRzl+K9Fp9W2UyvMz6Q==" }, "traverse": { "version": "0.6.6", @@ -16804,18 +16851,6 @@ "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==" }, - "ts-node": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", - "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - } - }, "ts-pnp": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", @@ -16843,14 +16878,14 @@ } }, "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", + "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", "requires": { "tslib": "^1.8.1" }, @@ -16921,19 +16956,19 @@ } }, "typescript": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", - "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" }, "ua-parser-js": { - "version": "0.7.20", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", - "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==" + "version": "0.7.24", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.24.tgz", + "integrity": "sha512-yo+miGzQx5gakzVK3QFfN0/L9uVhosXBBO7qmnk7c2iw1IhL212wfA3zbnI54B0obGwC/5NWub/iT9sReMx+Fw==" }, "uglify-js": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.1.tgz", - "integrity": "sha512-EWhx3fHy3M9JbaeTnO+rEqzCe1wtyQClv6q3YWq0voOj4E+bMZBErVS1GAHPDiRGONYq34M1/d8KuQMgvi6Gjw==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-TWYSWa9T2pPN4DIJYbU9oAjQx+5qdV5RUDxwARg8fmJZrD/V27Zj0JngW5xg1DFz42G0uDYl2XhzF6alSzD62w==", "optional": true }, "unbox-primitive": { @@ -17198,14 +17233,6 @@ "use-isomorphic-layout-effect": "^1.0.0" } }, - "utf-8-validate": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz", - "integrity": "sha512-jtJM6fpGv8C1SoH4PtG22pGto6x+Y8uPprW0tw3//gGFhDDTiuksgradgFN6yRayDP4SyZZa6ZMGHLIa17+M8A==", - "requires": { - "use-isomorphic-layout-effect": "^1.0.0" - } - }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -17783,8 +17810,7 @@ }, "ssri": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "resolved": "", "requires": { "figgy-pudding": "^3.5.1" } @@ -18210,9 +18236,9 @@ } }, "whatwg-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", - "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" }, "whatwg-mimetype": { "version": "2.3.0", @@ -18324,9 +18350,9 @@ }, "dependencies": { "@babel/runtime": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", - "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.9.tgz", + "integrity": "sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -18567,9 +18593,9 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" }, "yallist": { "version": "3.1.1", diff --git a/package.json b/package.json index 22104f5..775dc24 100644 --- a/package.json +++ b/package.json @@ -3,28 +3,29 @@ "version": "0.1.0", "private": true, "dependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.34", - "@fortawesome/free-solid-svg-icons": "^5.15.2", + "@fortawesome/fontawesome-svg-core": "^1.2.35", + "@fortawesome/free-solid-svg-icons": "^5.15.3", "@fortawesome/react-fontawesome": "^0.1.14", + "@rjsf/core": "^2.5.1", "babel-runtime": "^6.26.0", "bootstrap": "^4.6.0", - "classnames": "^2.2.6", - "d3": "^6.6.0", - "d3-array": "^2.12.0", + "classnames": "^2.3.1", + "d3": "^6.7.0", + "d3-array": "^2.12.1", "d3-axis": "^2.1.0", - "d3-scale": "^3.2.3", + "d3-scale": "^3.3.0", "d3-scale-chromatic": "^2.0.0", "d3-selection": "^2.0.0", "d3-shape": "^2.1.0", "d3-time-format": "^3.0.0", "es6-promise": "^4.2.8", "file-saver": "^2.0.5", - "flux": "^3.1.3", + "flux": "^4.0.1", "gaugeJS": "^1.3.7", - "handlebars": "^4.7.6", - "jquery": "^3.5.1", + "handlebars": "^4.7.7", + "jquery": "^3.6.0", "jsonwebtoken": "^8.5.1", - "jszip": "^3.5.0", + "jszip": "^3.6.0", "libcimsvg": "git+https://git.rwth-aachen.de/acs/public/cim/pintura-npm-package.git", "lodash": "^4.17.21", "moment": "^2.29.1", @@ -32,17 +33,17 @@ "multiselect-react-dropdown": "^1.6.11", "popper.js": "^1.16.1", "prop-types": "^15.7.2", - "rc-slider": "^9.7.1", - "react": "^16.14.0", + "rc-slider": "^9.7.2", + "react": "^17.0.2", "react-bootstrap": "^1.5.2", "react-collapse": "^5.1.0", "react-color": "^2.19.3", - "react-contexify": "^4.1.1", - "react-dnd": "^10.0.2", - "react-dnd-html5-backend": "^10.0.2", - "react-dom": "^16.14.0", + "react-contexify": "^5.0.0", + "react-dnd": "^13.1.1", + "react-dnd-html5-backend": "^12.1.1", + "react-dom": "^17.0.2", "react-fullscreenable": "^2.5.1-0", - "react-grid-system": "^7.1.1", + "react-grid-system": "^7.1.2", "react-json-view": "^1.21.3", "react-notification-system": "^0.4.0", "react-rnd": "^10.2.4", @@ -51,8 +52,8 @@ "react-svg-pan-zoom": "^3.10.0", "react-trafficlight": "^5.2.1", "superagent": "^6.1.0", - "swagger-ui-react": "^3.45.0", - "typescript": "^4.2.3" + "swagger-ui-react": "^3.47.1", + "typescript": "^4.2.4" }, "devDependencies": {}, "scripts": { diff --git a/src/app.js b/src/app.js index df1d61e..af3460a 100644 --- a/src/app.js +++ b/src/app.js @@ -17,7 +17,7 @@ import React from 'react'; import { DndProvider } from 'react-dnd'; -import HTML5Backend from 'react-dnd-html5-backend'; +import { HTML5Backend }from 'react-dnd-html5-backend'; import NotificationSystem from 'react-notification-system'; import { Redirect, Route } from 'react-router-dom'; import jwt from 'jsonwebtoken' @@ -30,12 +30,14 @@ import Header from './common/header'; import Menu from './common/menu'; import InfrastructureComponents from './ic/ics'; +import InfrastructureComponent from './ic/ic'; import Dashboard from './dashboard/dashboard'; import Scenarios from './scenario/scenarios'; import Scenario from './scenario/scenario'; import Users from './user/users'; import User from './user/user'; import APIBrowser from './common/api-browser'; +import LoginStore from './user/login-store' import './styles/app.css'; @@ -48,16 +50,20 @@ class App extends React.Component { constructor(props) { super(props); - AppDispatcher.dispatch({ - type: 'config/load', - }); + this.state = {} + } - this.state = {} + static getStores() { + return [LoginStore] } componentDidMount() { NotificationsDataManager.setSystem(this.refs.notificationSystem); + AppDispatcher.dispatch({ + type: 'config/load', + }); + // if token stored locally, we are already logged-in let token = localStorage.getItem("token"); if (token != null && token !== '') { @@ -70,7 +76,7 @@ class App extends React.Component { }); } else { let currentUser = JSON.parse(localStorage.getItem("currentUser")); - console.log("Already logged-in") + console.log("Logged-in as user ", currentUser.username) AppDispatcher.dispatch({ type: 'users/logged-in', token: token, @@ -115,7 +121,8 @@ class App extends React.Component { { pages.scenarios ? : '' } { pages.scenarios ? : '' } { pages.scenarios ? : '' } - { pages.infrastructure ? : '' } + { pages.infrastructure ? : '' } + { pages.infrastructure ? : '' } { pages.account ? : '' } { pages.users ? : '' } { pages.api ? : '' } diff --git a/src/common/api-browser.js b/src/common/api-browser.js index b1e7375..08e7e57 100644 --- a/src/common/api-browser.js +++ b/src/common/api-browser.js @@ -39,7 +39,7 @@ class APIBrowser extends React.Component { return spec; } - componentWillMount() { + componentDidMount() { this._asyncRequest = RestAPI.get('/api/v2/openapi') .then((spec) => { this._asyncRequest = null; diff --git a/src/common/icon-button.js b/src/common/icon-button.js index 5a7fe8d..2a65b95 100644 --- a/src/common/icon-button.js +++ b/src/common/icon-button.js @@ -25,31 +25,32 @@ import Icon from '../common/icon'; class IconButton extends React.Component { render() { - const altButtonStyle = { - marginLeft: '10px', + let btn = + + let button; + if (!this.props.tooltip || this.props.hidetooltip) { + button = btn; + } else { + button = {this.props.tooltip}} > + {btn} + } - const iconStyle = { - height: '30px', - width: '30px' - } - - return {this.props.tooltip}} > - - + return button; } } diff --git a/src/common/icon-toggle-button.js b/src/common/icon-toggle-button.js new file mode 100644 index 0000000..e9adc8a --- /dev/null +++ b/src/common/icon-toggle-button.js @@ -0,0 +1,62 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from 'react'; + +import { ToggleButton, ButtonGroup, Tooltip, OverlayTrigger } from 'react-bootstrap'; + +import Icon from './icon'; + + +class IconToggleButton extends React.Component { + + render() { + let tooltip = this.props.checked ? this.props.tooltipChecked : this.props.tooltipUnchecked; + + return {tooltip}} > + + + {this.props.checked ? + + : + + } + + + + } +} + +export default IconToggleButton; diff --git a/src/common/menu.js b/src/common/menu.js index 5d661cf..1c1ac6f 100644 --- a/src/common/menu.js +++ b/src/common/menu.js @@ -59,11 +59,7 @@ class SidebarMenu extends React.Component { AppDispatcher.dispatch({ type: 'users/logout' }); - // The Login Store is deleted automatically - - // discard login token and current User - localStorage.setItem('token', ''); - localStorage.setItem('currentUser', ''); + // The Login Store and local storage are deleted automatically } render() { diff --git a/src/common/table-column.js b/src/common/table-column.js index fb9905a..042010b 100644 --- a/src/common/table-column.js +++ b/src/common/table-column.js @@ -27,7 +27,10 @@ class TableColumn extends Component { deleteButton: false, showDeleteButton: null, exportButton: false, + signalButton: false, duplicateButton: false, + isLocked: null, + locked: false, link: '/', linkKey: '', dataIndex: false, diff --git a/src/common/table.js b/src/common/table.js index 8abe5a9..8ea1579 100644 --- a/src/common/table.js +++ b/src/common/table.js @@ -20,6 +20,9 @@ import _ from 'lodash'; import { Table, Button, Form, Tooltip, OverlayTrigger } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import Icon from './icon'; +import IconToggleButton from './icon-toggle-button'; +import IconButton from '../common/icon-button'; + class CustomTable extends Component { constructor(props) { @@ -45,6 +48,7 @@ class CustomTable extends Component { static addCell(data, index, child) { // add data to cell let content = null; + let childkey = 0; if ('dataKeys' in child.props) { for (let key of child.props.dataKeys) { @@ -90,7 +94,7 @@ class CustomTable extends Component { onClick={() => child.props.onDownload(contentkey)} disabled={child.props.onDownload == null}> {contentkey + ' '} - + ); }); @@ -125,26 +129,26 @@ class CustomTable extends Component { cell.push(index); } + let isLocked = child.props.locked || (child.props.isLocked != null && child.props.isLocked(index)); + // add buttons - let showEditButton = child.props.showEditButton !== null && child.props.showEditButton !== undefined + let showEditButton = child.props.showEditButton !== null && child.props.showEditButton !== undefined ? child.props.showEditButton(index) : true; if (child.props.editButton && showEditButton) { cell.push( - Edit } - > - - - ); + child.props.onEdit(index)} + variant={'table-control-button'} + />) } if (child.props.checkbox) { @@ -164,89 +168,112 @@ class CustomTable extends Component { ); } + if (child.props.lockButton) { + cell.push( + child.props.onChangeLock(index)} + checked={isLocked} + checkedIcon='lock' + uncheckedIcon='lock-open' + tooltipChecked='Scenario is locked, cannot be edited' + tooltipUnchecked='Scenario is unlocked, can be edited' + disabled={false} + variant={'table-control-button'} + /> + ); + } + if (child.props.exportButton) { cell.push( - Export } - > - - - ); + child.props.onExport(index)} + variant={'table-control-button'} + />); + } + + if (child.props.signalButton) { + cell.push( + child.props.onAutoConf(index)} + variant={'table-control-button'} + />); } if (child.props.duplicateButton) { cell.push( - Duplicate } > - - - ); + child.props.onDuplicate(index)} + variant={'table-control-button'} + />); } if (child.props.addRemoveFilesButton) { cell.push( - Add/remove File(s)} > - - - ); + child.props.onAddRemove(index)} + variant={'table-control-button'} + />); } if (child.props.downloadAllButton) { cell.push( - Download All Files} > - - - ); + child.props.onDownloadAll(index)} + variant={'table-control-button'} + />); } - let showDeleteButton = child.props.showDeleteButton !== null && child.props.showDeleteButton !== undefined + let showDeleteButton = child.props.showDeleteButton !== null && child.props.showDeleteButton !== undefined ? child.props.showDeleteButton(index) : true; if (child.props.deleteButton && showDeleteButton) { cell.push( - Delete } > - - - ); + child.props.onDelete(index)} + variant={'table-control-button'} + />); } return cell; @@ -290,7 +317,10 @@ class CustomTable extends Component { const row = []; for (let child of props.children) { - row.push(CustomTable.addCell(data, index, child)); + // check whether empty <> object has been given + if (Object.keys(child.props).length !== 0) { + row.push(CustomTable.addCell(data, index, child)); + } } return row; @@ -348,14 +378,14 @@ class CustomTable extends Component { value={cell} onChange={(event) => children[cellIndex].props.onInlineChange(event, rowIndex, cellIndex)} ref={ref => { this.activeInput = ref; }} /> - : + : { cell.map((element, elementIndex) => {element} ) } - } + } }) } diff --git a/src/componentconfig/config-table.js b/src/componentconfig/config-table.js new file mode 100644 index 0000000..665850e --- /dev/null +++ b/src/componentconfig/config-table.js @@ -0,0 +1,462 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, {Component} from "react"; +import FileSaver from 'file-saver'; +import IconButton from "../common/icon-button"; +import Table from "../common/table"; +import TableColumn from "../common/table-column"; +import DeleteDialog from "../common/dialogs/delete-dialog"; +import AppDispatcher from "../common/app-dispatcher"; +import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; +import ICAction from "../ic/ic-action"; +import EditConfigDialog from "./edit-config"; +import ImportConfigDialog from "./import-config"; +import EditSignalMappingDialog from "../signal/edit-signal-mapping"; + +class ConfigTable extends Component { + + constructor() { + super(); + + this.state = { + editConfigModal: false, + modalConfigData: {}, + modalConfigIndex: 0, + deleteConfigModal: false, + importConfigModal: false, + newConfig: false, + selectedConfigs: [], + ExternalICInUse: false, + editOutputSignalsModal: false, + editInputSignalsModal: false, + } + } + + static getDerivedStateFromProps(props, state){ + + let ExternalICInUse = false + + for (let config of props.configs){ + for (let component of props.ics) { + if ((config.icID === component.id) && (component.managedexternally === true)) { + ExternalICInUse = true; + break; + } + } + } + + return { + ExternalICInUse: ExternalICInUse + }; + } + + addConfig() { + const config = { + scenarioID: this.props.scenario.id, + name: 'New Component Configuration', + icID: this.props.ics.length > 0 ? this.props.ics[0].id : null, + startParameters: {}, + }; + + AppDispatcher.dispatch({ + type: 'configs/start-add', + data: config, + token: this.props.sessionToken + }); + + this.setState({ newConfig: true }); + + } + + closeEditConfigModal(data) { + this.setState({ editConfigModal: false, newConfig: false }); + + if (data) { + AppDispatcher.dispatch({ + type: 'configs/start-edit', + data: data, + token: this.props.sessionToken, + }); + } + } + + closeDeleteConfigModal(confirmDelete) { + this.setState({ deleteConfigModal: false }); + + if (confirmDelete === false) { + return; + } + + AppDispatcher.dispatch({ + type: 'configs/start-remove', + data: this.state.modalConfigData, + token: this.props.sessionToken + }); + } + + importConfig(data) { + this.setState({ importConfigModal: false }); + + if (data == null) { + return; + } + + let newConfig = JSON.parse(JSON.stringify(data.config)) + + newConfig["scenarioID"] = this.props.scenario.id; + newConfig.name = data.name; + + AppDispatcher.dispatch({ + type: 'configs/start-add', + data: newConfig, + token: this.props.sessionToken + }); + } + + copyConfig(index) { + let config = JSON.parse(JSON.stringify(this.props.configs[index])); + + let signals = JSON.parse(JSON.stringify(this.props.signals.filter(s => s.configID === parseInt(config.id, 10)))); + signals.forEach((signal) => { + delete signal.configID; + delete signal.id; + }) + + // two separate lists for inputMapping and outputMapping + let inputSignals = signals.filter(s => s.direction === 'in'); + let outputSignals = signals.filter(s => s.direction === 'out'); + + // add signal mappings to config + config["inputMapping"] = inputSignals; + config["outputMapping"] = outputSignals; + + delete config.id; + delete config.scenarioID; + delete config.inputLength; + delete config.outputLength; + + return config; + } + + exportConfig(index) { + let config = this.copyConfig(index); + + // show save dialog + const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' }); + FileSaver.saveAs(blob, 'config-' + config.name + '.json'); + } + + duplicateConfig(index) { + let newConfig = this.copyConfig(index); + newConfig["scenarioID"] = this.props.scenario.id; + newConfig.name = newConfig.name + '_copy'; + + AppDispatcher.dispatch({ + type: 'configs/start-add', + data: newConfig, + token: this.props.sessionToken + }); + } + + onConfigChecked(index, event) { + const selectedConfigs = Object.assign([], this.state.selectedConfigs); + for (let key in selectedConfigs) { + if (selectedConfigs[key] === index) { + // update existing entry + if (event.target.checked) { + return; + } + + selectedConfigs.splice(key, 1); + + this.setState({ selectedConfigs: selectedConfigs }); + return; + } + } + + // add new entry + if (event.target.checked === false) { + return; + } + + selectedConfigs.push(index); + this.setState({ selectedConfigs: selectedConfigs }); + } + + usesExternalIC(index) { + for (let component of this.props.ics) { + if (component.id === this.props.configs[index].icID) { + if (component.managedexternally === true) { + return true + } + } + } + return false + } + + getICName(icID) { + for (let ic of this.props.ics) { + if (ic.id === icID) { + return ic.name || ic.uuid; + } + } + } + + /* ############################################## + * Signal modification methods + ############################################## */ + + closeEditSignalsModal(direction) { + + // reload the config + AppDispatcher.dispatch({ + type: 'configs/start-load', + data: this.state.modalConfigData.id, + token: this.props.sessionToken + }); + + if (direction === "in") { + this.setState({ editInputSignalsModal: false }); + } else if (direction === "out") { + this.setState({ editOutputSignalsModal: false }); + } + } + + signalsAutoConf(index) { + let componentConfig = this.props.configs[index]; + // determine apiurl of infrastructure component + let ic = this.props.ics.find(ic => ic.id === componentConfig.icID) + if (!ic.type.includes("villas-node")) { + let message = "Cannot autoconfigure signals for IC type " + ic.type + " of category " + ic.category + ". This is only possible for gateway ICs of type 'VILLASnode'." + console.warn(message); + + const SIGNAL_AUTOCONF_WARN_NOTIFICATION = { + title: 'Failed to load signal config for IC ' + ic.name, + message: message, + level: 'warning' + }; + NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_WARN_NOTIFICATION); + return; + } + + let splitWebsocketURL = ic.websocketurl.split("/") + + AppDispatcher.dispatch({ + type: 'signals/start-autoconfig', + url: ic.apiurl + "/nodes", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: this.props.sessionToken, + configID: componentConfig.id + }); + + } + + startPintura(configIndex) { + let config = this.props.configs[configIndex]; + + // get xml / CIM file + let files = [] + for (let id of config.fileIDs) { + for (let file of this.props.files) { + if (file.id === id && ['xml'].some(e => file.type.includes(e))) { + files.push(file); + } + } + } + + if (files.length > 1) { + // more than one CIM file... + console.warn("There is more than one CIM file selected in this component configuration. I will open them all in a separate tab.") + } + + let baseURL = 'aaa.bbb.ccc.ddd/api/v2/files/' + for (let file of files) { + // endpoint param serves for download and upload of CIM file, token is required for authentication + let params = { + token: this.props.sessionToken, + endpoint: baseURL + String(file.id), + } + + // TODO start Pintura for editing CIM/ XML file from here + console.warn("Starting Pintura... and nothing happens so far :-) ", params) + } + } + + render() { + const buttonStyle = { + marginLeft: '10px', + } + + const iconStyle = { + height: '30px', + width: '30px' + } + + return ( +
+ {/*Component Configurations table*/} +

Component Configurations + + this.addConfig()} + icon='plus' + disabled={this.props.locked} + hidetooltip={this.props.locked} + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + this.setState({ importConfigModal: true })} + icon='upload' + disabled={this.props.locked} + hidetooltip={this.props.locked} + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + +

+ + !this.usesExternalIC(index)} + onChecked={(index, event) => this.onConfigChecked(index, event)} + width={20} + /> + {this.props.currentUser.role === "Admin" ? + + : <> + } + + this.setState({ editOutputSignalsModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })} + width={150} + locked={this.props.locked} + /> + this.setState({ editInputSignalsModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })} + width={150} + locked={this.props.locked} + /> + this.signalsAutoConf(index)} + width={170} + locked={this.props.locked} + /> + this.getICName(icID)} + width={200} + /> + this.setState({ editConfigModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })} + onDelete={(index) => this.setState({ deleteConfigModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })} + onExport={index => this.exportConfig(index)} + onDuplicate={index => this.duplicateConfig(index)} + locked={this.props.locked} + /> +
+ + {this.state.ExternalICInUse ? +
+ this.copyConfig(index)} + token = {this.props.sessionToken} + actions={[ + { id: '0', title: 'Start', data: { action: 'start' } }, + { id: '1', title: 'Stop', data: { action: 'stop' } }, + { id: '2', title: 'Pause', data: { action: 'pause' } }, + { id: '3', title: 'Resume', data: { action: 'resume' } } + ]} /> +
+ :
+ } + +
+ + this.closeEditConfigModal(data)} + config={this.state.modalConfigData} + ics={this.props.ics} + files={this.props.files} + sessionToken={this.props.sessionToken} + /> + this.importConfig(data)} + ics={this.props.ics} + /> + this.closeDeleteConfigModal(c)} + /> + this.closeEditSignalsModal(direction)} + direction="Output" + signals={this.props.signals} + configID={this.state.modalConfigData.id} + sessionToken={this.props.sessionToken} + /> + this.closeEditSignalsModal(direction)} + direction="Input" + signals={this.props.signals} + configID={this.state.modalConfigData.id} + sessionToken={this.props.sessionToken} + /> +
+ ) + } +} + +export default ConfigTable; diff --git a/src/dashboard/dashboard-button-group.js b/src/dashboard/dashboard-button-group.js index 20a8994..ddacfa0 100644 --- a/src/dashboard/dashboard-button-group.js +++ b/src/dashboard/dashboard-button-group.js @@ -17,115 +17,77 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Button,OverlayTrigger, Tooltip } from 'react-bootstrap'; -import Icon from "../common/icon"; +import IconButton from '../common/icon-button'; + +const buttonStyle = { + marginLeft: '12px', + height: '44px', + width: '35px', +}; + +const iconStyle = { + height: '25px', + width: '25px' +} + +let buttonkey = 0; class DashboardButtonGroup extends React.Component { - render() { - const buttonStyle = { - marginLeft: '12px', - height: '44px', - width : '35px', - }; - const iconStyle = { - height: '25px', - width : '25px' + getBtn(icon, tooltip, clickFn, locked = false) { + if (locked) { + return + } else { + return } + } + render() { const buttons = []; - let key = 0; - - /*if (this.props.fullscreen) { - return null; - }*/ + buttonkey = 0; if (this.props.editing) { - buttons.push( - Save changes } > - - , - Discard changes } > - - - ); + buttons.push(this.getBtn("save", "Save changes", this.props.onSave)); + buttons.push(this.getBtn("times", "Discard changes", this.props.onCancel)); } else { if (this.props.fullscreen !== true) { - buttons.push( - - Change to fullscreen view } > - - - ); + buttons.push(this.getBtn("expand", "Change to fullscreen view", this.props.onFullscreen)); } else { - buttons.push( - Back to normal view } > - - - ); + buttons.push(this.getBtn("compress", "Back to normal view", this.props.onFullscreen)); } if (this.props.paused) { - buttons.push( - Continue simulation } > - - - ); + buttons.push(this.getBtn("play", "Continue simulation", this.props.onUnpause)); } else { - buttons.push( - Pause simulation } > - - - ); + buttons.push(this.getBtn("pause", "Pause simulation", this.props.onPause)); } if (this.props.fullscreen !== true) { - buttons.push( - Add, edit or delete files of scenario }> - - - ); - - buttons.push( - Add, edit or delete input signals }> - - - ); - - buttons.push( - Add, edit or delete output signals }> - - - ); - - buttons.push( - Add widgets and edit layout }> - - - ); + let tooltip = this.props.locked ? "View files of scenario" : "Add, edit or delete files of scenario"; + buttons.push(this.getBtn("file", tooltip, this.props.onEditFiles)); + buttons.push(this.getBtn("sign-in-alt", "Add, edit or delete input signals", this.props.onEditInputSignals, this.props.locked)); + buttons.push(this.getBtn("sign-out-alt", "Add, edit or delete output signals", this.props.onEditOutputSignals, this.props.locked)); + buttons.push(this.getBtn("pen", "Add widgets and edit layout", this.props.onEdit, this.props.locked)); } } diff --git a/src/dashboard/dashboard-table.js b/src/dashboard/dashboard-table.js new file mode 100644 index 0000000..589366b --- /dev/null +++ b/src/dashboard/dashboard-table.js @@ -0,0 +1,246 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, {Component} from "react"; +import FileSaver from 'file-saver'; +import IconButton from "../common/icon-button"; +import Table from "../common/table"; +import TableColumn from "../common/table-column"; +import NewDashboardDialog from "./new-dashboard"; +import EditDashboardDialog from "./edit-dashboard"; +import ImportDashboardDialog from "./import-dashboard"; +import DeleteDialog from "../common/dialogs/delete-dialog"; +import AppDispatcher from "../common/app-dispatcher"; + +class DashboardTable extends Component { + + constructor() { + super(); + + this.state = { + newDashboardModal: false, + deleteDashboardModal: false, + importDashboardModal: false, + modalDashboardData: {}, + dashboardEditModal: false, + } + } + + closeNewDashboardModal(data) { + this.setState({ newDashboardModal: false }); + if (data) { + // TODO: 'newDashboard' not used, check this + let newDashboard = data; + // add default grid value and scenarioID + newDashboard["grid"] = 15; + newDashboard["scenarioID"] = this.props.scenario.id; + + AppDispatcher.dispatch({ + type: 'dashboards/start-add', + data, + token: this.props.sessionToken, + }); + } + } + + closeEditDashboardModal(data) { + this.setState({ dashboardEditModal: false }); + + let editDashboard = this.state.modalDashboardData; + + if (data != null) { + editDashboard.name = data.name; + AppDispatcher.dispatch({ + type: 'dashboards/start-edit', + data: editDashboard, + token: this.props.sessionToken + }); + } + } + + closeDeleteDashboardModal(confirmDelete) { + this.setState({ deleteDashboardModal: false }); + + if (confirmDelete === false) { + return; + } + + AppDispatcher.dispatch({ + type: 'dashboards/start-remove', + data: this.state.modalDashboardData, + token: this.props.sessionToken, + }); + } + + closeImportDashboardModal(data) { + this.setState({ importDashboardModal: false }); + + if (data) { + let newDashboard = JSON.parse(JSON.stringify(data)); + newDashboard["scenarioID"] = this.props.scenario.id; + + AppDispatcher.dispatch({ + type: 'dashboards/start-add', + data: newDashboard, + token: this.props.sessionToken, + }); + } + } + + copyDashboard(index) { + let dashboard = JSON.parse(JSON.stringify(this.props.dashboards[index])); + + let widgets = JSON.parse(JSON.stringify(this.props.widgets.filter(w => w.dashboardID === parseInt(dashboard.id, 10)))); + widgets.forEach((widget) => { + delete widget.dashboardID; + delete widget.id; + }) + dashboard["widgets"] = widgets; + delete dashboard.scenarioID; + delete dashboard.id; + + return dashboard; + } + + exportDashboard(index) { + let dashboard = this.copyDashboard(index); + + // show save dialog + const blob = new Blob([JSON.stringify(dashboard, null, 2)], { type: 'application/json' }); + FileSaver.saveAs(blob, 'dashboard - ' + dashboard.name + '.json'); + } + + duplicateDashboard(index) { + let newDashboard = this.copyDashboard(index); + newDashboard.scenarioID = this.props.scenario.id; + newDashboard.name = newDashboard.name + '_copy'; + + AppDispatcher.dispatch({ + type: 'dashboards/start-add', + data: newDashboard, + token: this.props.sessionToken, + }); + } + + render() { + const buttonStyle = { + marginLeft: '10px', + } + + const iconStyle = { + height: '30px', + width: '30px' + } + + return ( +
+ {/*Dashboard table*/} +

Dashboards + + this.setState({newDashboardModal: true})} + icon='plus' + disabled={this.props.locked} + hidetooltip={this.props.locked} + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + this.setState({importDashboardModal: true})} + icon='upload' + disabled={this.props.locked} + hidetooltip={this.props.locked} + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + +

+ + {this.props.currentUser.role === "Admin" ? + + : <> + } + + + + this.setState({ + dashboardEditModal: true, + modalDashboardData: this.props.dashboards[index] + })} + onDelete={(index) => this.setState({ + deleteDashboardModal: true, + modalDashboardData: this.props.dashboards[index], + modalDashboardIndex: index + })} + onExport={index => this.exportDashboard(index)} + onDuplicate={index => this.duplicateDashboard(index)} + locked={this.props.locked} + /> +
+ + this.closeNewDashboardModal(data)} + /> + this.closeEditDashboardModal(data)} + /> + this.closeImportDashboardModal(data)} + /> + this.closeDeleteDashboardModal(e)} + /> + +
+ ) + } +} + +export default DashboardTable; diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js index fe3ca4f..ee838f3 100644 --- a/src/dashboard/dashboard.js +++ b/src/dashboard/dashboard.js @@ -27,6 +27,7 @@ import WidgetContextMenu from '../widget/widget-context-menu'; import WidgetToolbox from '../widget/widget-toolbox'; import WidgetArea from '../widget/widget-area'; import DashboardButtonGroup from './dashboard-button-group'; +import IconToggleButton from '../common/icon-toggle-button'; import DashboardStore from './dashboard-store'; import SignalStore from '../signal/signal-store' @@ -35,6 +36,8 @@ import WidgetStore from '../widget/widget-store'; import ICStore from '../ic/ic-store' import ConfigStore from '../componentconfig/config-store' import AppDispatcher from '../common/app-dispatcher'; +import ScenarioStore from '../scenario/scenario-store'; + import 'react-contexify/dist/ReactContexify.min.css'; import WidgetContainer from '../widget/widget-container'; @@ -45,7 +48,7 @@ class Dashboard extends Component { static lastWidgetKey = 0; static webSocketsOpened = false; static getStores() { - return [DashboardStore, FileStore, WidgetStore, SignalStore, ConfigStore, ICStore]; + return [DashboardStore, FileStore, WidgetStore, SignalStore, ConfigStore, ICStore, ScenarioStore]; } static calculateState(prevState, props) { @@ -80,9 +83,14 @@ class Dashboard extends Component { // filter component configurations to the ones that belong to this scenario let configs = []; let files = []; + let locked = false; if (dashboard !== undefined) { configs = ConfigStore.getState().filter(config => config.scenarioID === dashboard.scenarioID); files = FileStore.getState().filter(file => file.scenarioID === dashboard.scenarioID); + let scenario = ScenarioStore.getState().find(s => s.id === dashboard.scenarioID); + if (scenario) { + locked = scenario.isLocked; + } if (dashboard.height === 0) { dashboard.height = 400; } @@ -144,6 +152,7 @@ class Dashboard extends Component { widgetOrigIDs: prevState.widgetOrigIDs || [], maxWidgetHeight: maxHeight || null, + locked, }; } @@ -177,11 +186,22 @@ class Dashboard extends Component { componentDidUpdate(prevProps: Readonly

, prevState: Readonly, snapshot: SS) { // open web sockets if ICs are already known and sockets are not opened yet if (this.state.ics !== undefined && !Dashboard.webSocketsOpened) { - if (this.state.ics.length > 0) { - console.log("Starting to open IC websockets:", this.state.ics); + // only open sockets of ICs with configured input or output signals + let relevantICs = this.state.ics.filter(ic => { + let result = false; + this.state.configs.forEach(config => { + if(ic.id === config.icID && (config.inputLength !== 0 || config.outputLength !== 0)){ + result = true; + } + }) + return result; + }) + + if (relevantICs.length > 0) { + console.log("Starting to open IC websockets:", relevantICs); AppDispatcher.dispatch({ type: 'ics/open-sockets', - data: this.state.ics + data: relevantICs }); Dashboard.webSocketsOpened = true; @@ -205,6 +225,13 @@ class Dashboard extends Component { param: '?scenarioID=' + this.state.dashboard.scenarioID, token: this.state.sessionToken }); + + // load scenario for 'isLocked' value + AppDispatcher.dispatch({ + type: 'scenarios/start-load', + data: this.state.dashboard.scenarioID, + token: this.state.sessionToken + }); } } @@ -471,66 +498,65 @@ class Dashboard extends Component { return

{"Loading Dashboard..."}
} + const buttonStyle = { + marginLeft: '10px', + } + + const iconStyle = { + height: '25px', + width: '25px' + } + const grid = this.state.dashboard.grid; const boxClasses = classNames('section', 'box', { 'fullscreen-padding': this.props.isFullscreen }); let draggable = this.state.editing; let dropZoneHeight = this.state.dashboard.height; - return
+ return (
-

{this.state.dashboard.name}

+

+ {this.state.dashboard.name} + + + +

- -
+ +
-
e.preventDefault()}> - {this.state.editing && - - } - {!draggable ? ( - - {this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => ( - - - - ))} - - ) : ( - +
e.preventDefault()}> + {this.state.editing && + + } + {!draggable ? ( + {this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => ( - + - + ))} + ) : ( + + {this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => ( + + + + ))} + - + )} - + - this.closeEditSignalsModal(direction)} - direction="Output" - signals={this.state.signals} - configID={null} - configs={this.state.configs} - sessionToken={this.state.sessionToken} - /> - this.closeEditSignalsModal(direction)} - direction="Input" - signals={this.state.signals} - configID={null} - configs={this.state.configs} - sessionToken={this.state.sessionToken} - /> + + + this.closeEditSignalsModal(direction)} + direction="Output" + signals={this.state.signals} + configID={null} + configs={this.state.configs} + sessionToken={this.state.sessionToken} + /> + this.closeEditSignalsModal(direction)} + direction="Input" + signals={this.state.signals} + configID={null} + configs={this.state.configs} + sessionToken={this.state.sessionToken} + /> + + +
-
; + ); } } diff --git a/src/file/edit-files.js b/src/file/edit-files.js index 1ec0276..bca36b6 100644 --- a/src/file/edit-files.js +++ b/src/file/edit-files.js @@ -106,10 +106,12 @@ class EditFilesDialog extends React.Component { marginTop: '-40px' }; + let title = this.props.locked ? "View files of scenario" : "Edit Files of Scenario"; + return ( this.onClose()} blendOutCancel = {true} @@ -139,6 +141,7 @@ class EditFilesDialog extends React.Component { onDelete={(index) => this.deleteFile(index)} editButton onEdit={index => this.setState({ editModal: true, modalFile: this.props.files[index] })} + locked={this.props.locked} /> @@ -146,13 +149,17 @@ class EditFilesDialog extends React.Component {
Add file
- this.selectUploadFile(event)} /> + this.selectUploadFile(event)} + disabled={this.props.locked} + /> diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js deleted file mode 100644 index 197eb45..0000000 --- a/src/ic/ic-dialog.js +++ /dev/null @@ -1,173 +0,0 @@ -import React from 'react'; -import { Button, Row, Col } from 'react-bootstrap'; -import Dialog from '../common/dialogs/dialog'; -import Icon from "../common/icon"; -import ConfirmCommand from './confirm-command'; -import ReactJson from 'react-json-view'; -import FileSaver from 'file-saver'; -import moment from 'moment'; - -class ICDialog extends React.Component { - valid = true; - - constructor(props) { - super(props); - - this.state = { - confirmCommand: false, - command: '', - }; - } - - onClose(canceled) { - this.props.onClose(); - } - - handleChange(e) { - - } - - showFurtherInfo(key){ - if(typeof this.state[key] === 'undefined') this.setState({[key]: false}); - this.setState({[key]: !this.state[key]}); - } - - closeConfirmModal(canceled){ - if(!canceled){ - this.props.sendControlCommand(this.state.command,this.props.ic); - } - - this.setState({confirmCommand: false, command: ''}); - } - - async downloadGraph(url) { - - let blob = await fetch(url).then(r => r.blob()) - FileSaver.saveAs(blob, this.props.ic.name + ".svg"); - } - - render() { - - let graphURL = "" - if (this.props.ic.apiurl !== ""){ - graphURL = this.props.ic.apiurl + "/graph.svg" - } - - return ( - this.onClose(c)} - valid={true} - size='xl' - blendOutCancel={true} - > -
- - - - Name - {this.props.ic.name} - - - UUID - {this.props.ic.uuid} - - - State - {this.props.ic.state} - - - Category - {this.props.ic.category} - - - Type - {this.props.ic.type} - - - Uptime - {moment.duration(this.props.ic.uptime, "seconds").humanize()} - - - Location - {this.props.ic.location} - - - Description - {this.props.ic.description} - - - Websocket URL - {this.props.ic.websocketurl} - - - API URL - {this.props.ic.apiurl} - - - Start parameter schema - - - - - - - -
Raw Status:
- - - {this.props.ic.type === "villas-node" ? - <> -
- -
-
Graph:
-
- {"Graph -
- - {this.props.user.role === "Admin" ? -
-
Controls:
-
- - -
-
- :
- } - this.closeConfirmModal(c)}/> - - :
- } - - - -
- ); - } -} - -export default ICDialog; diff --git a/src/ic/ic.js b/src/ic/ic.js new file mode 100644 index 0000000..9bb730f --- /dev/null +++ b/src/ic/ic.js @@ -0,0 +1,240 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from 'react'; +import InfrastructureComponentStore from './ic-store'; +import { Container as FluxContainer } from 'flux/utils'; +import AppDispatcher from '../common/app-dispatcher'; +import { Container, Col, Row, Table, Button } from 'react-bootstrap'; +import moment from 'moment'; +import ReactJson from 'react-json-view'; +import ConfirmCommand from './confirm-command'; +import Icon from "../common/icon"; + + + +class InfrastructureComponent extends React.Component { + constructor(props) { + super(props); + + this.state = { + confirmCommand: false, + command: '', + }; + } + + static getStores() { + return [InfrastructureComponentStore]; + } + + static calculateState(prevState, props) { + if (prevState == null) { + prevState = {}; + } + + return { + sessionToken: localStorage.getItem("token"), + currentUser: JSON.parse(localStorage.getItem("currentUser")), + ic: InfrastructureComponentStore.getState().find(ic => ic.id === parseInt(props.match.params.ic, 10)) + } + } + + componentDidMount() { + let icID = parseInt(this.props.match.params.ic, 10); + + AppDispatcher.dispatch({ + type: 'ics/start-load', + data: icID, + token: this.state.sessionToken, + }); + } + + isJSON(data) { + if (data === undefined || data === null) { + return false; + } + let str = JSON.stringify(data); + try { + JSON.parse(str) + } + catch (ex) { + return false + } + return true + } + + async downloadGraph(url) { + let blob = await fetch(url).then(r => r.blob()) + FileSaver.saveAs(blob, this.state.ic.name + ".svg"); + } + + sendControlCommand() { + if (this.state.command === "restart") { + AppDispatcher.dispatch({ + type: 'ics/restart', + url: this.state.ic.apiurl + "/restart", + token: this.state.sessionToken, + }); + } else if (this.state.command === "shutdown") { + AppDispatcher.dispatch({ + type: 'ics/shutdown', + url: this.state.ic.apiurl + "/shutdown", + token: this.state.sessionToken, + }); + } + } + + confirmCommand(canceled){ + if(!canceled){ + this.sendControlCommand(); + } + + this.setState({confirmCommand: false, command: ''}); + } + + async downloadGraph(url) { + + let blob = await fetch(url).then(r => r.blob()) + FileSaver.saveAs(blob, this.props.ic.name + ".svg"); + } + + render() { + if (this.state.ic === undefined) { + return

Loading Infrastructure Component...

; + } + + let graphURL = "" + if (this.state.ic.apiurl !== "") { + graphURL = this.state.ic.apiurl + "/graph.svg" + } + + return
+

{this.state.ic.name}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name{this.state.ic.name}
Description{this.state.ic.description}
UUID{this.state.ic.uuid}
State{this.state.ic.state}
Category{this.state.ic.category}
Type{this.state.ic.type}
Uptime{moment.duration(this.state.ic.uptime, "seconds").humanize()}
Location{this.state.ic.location}
Websocket URL{this.state.ic.websocketurl}
API URL{this.state.ic.apiurl}
Start parameter schema + +
+ + Raw Status + {this.isJSON(this.state.ic.statusupdateraw) ? + :
No valid JSON raw data available.
} + + {this.state.ic.type === "villas-node" ? + <> +
+ +
+
+ Graph: +
+ {"Graph +
+ + {this.state.currentUser.role === "Admin" ? +
+
+ Controls: +
+ + +
+
+ :
+ } + this.confirmCommand(c)} /> + + :
} + + + + +
; + } + +} + +let fluxContainerConverter = require('../common/FluxContainerConverter'); +export default FluxContainer.create(fluxContainerConverter.convert(InfrastructureComponent), { withProps: true }); \ No newline at end of file diff --git a/src/ic/ics.js b/src/ic/ics.js index 3ff80c1..7698317 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -17,7 +17,7 @@ import React, { Component } from 'react'; import { Container } from 'flux/utils'; -import { Button, Badge } from 'react-bootstrap'; +import { Badge } from 'react-bootstrap'; import FileSaver from 'file-saver'; import _ from 'lodash'; import moment from 'moment' @@ -32,7 +32,6 @@ import TableColumn from '../common/table-column'; import NewICDialog from './new-ic'; import EditICDialog from './edit-ic'; import ImportICDialog from './import-ic'; -import ICDialog from './ic-dialog'; import ICAction from './ic-action'; import DeleteDialog from '../common/dialogs/delete-dialog'; @@ -367,32 +366,11 @@ class InfrastructureComponents extends Component { } } - modifyNameColumn(name, component){ - let index = this.state.ics.indexOf(component); - return - } - openICStatus(ic){ let index = this.state.ics.indexOf(ic); this.setState({ icModal: true, modalIC: ic, modalIndex: index }) } - sendControlCommand(command,ic){ - if(command === "restart"){ - AppDispatcher.dispatch({ - type: 'ics/restart', - url: ic.apiurl + "/restart", - token: this.state.sessionToken, - }); - }else if(command === "shutdown"){ - AppDispatcher.dispatch({ - type: 'ics/shutdown', - url: ic.apiurl + "/shutdown", - token: this.state.sessionToken, - }); - } - } - isLocalIC(index, ics){ let ic = ics[index] return !ic.managedexternally @@ -419,7 +397,8 @@ class InfrastructureComponents extends Component { this.modifyNameColumn(name, component)} + link='/infrastructure/' + linkKey='id' /> this.setState({newModal: true})} icon='plus' /> this.setState({importModal: true})} icon='upload' @@ -538,13 +517,6 @@ class InfrastructureComponents extends Component { this.closeEditModal(data)} ic={this.state.modalIC} /> this.closeImportModal(data)} /> this.closeDeleteModal(e)} /> - this.closeICModal(data)} - ic={this.state.modalIC} - token={this.state.sessionToken} - user={this.state.currentUser} - sendControlCommand={(command, ic) => this.sendControlCommand(command, ic)}/>
); } diff --git a/src/ic/new-ic.js b/src/ic/new-ic.js index 3fe9fb8..cb5c8c0 100644 --- a/src/ic/new-ic.js +++ b/src/ic/new-ic.js @@ -56,6 +56,12 @@ class NewICDialog extends React.Component { const data = { managedexternally: this.state.managedexternally, manager: this.state.manager, + name: this.state.name, + type: this.state.type, + category: this.state.category, + uuid: this.state.uuid, + description: this.state.description, + location: this.state.location, parameters: parameters }; @@ -65,10 +71,12 @@ class NewICDialog extends React.Component { if (this.state.websocketurl != null && this.state.websocketurl !== "") { parameters.websocketurl = this.state.websocketurl; + data.websocketurl = this.state.websocketurl; } if (this.state.apiurl != null && this.state.apiurl !== "") { parameters.apiurl = this.state.apiurl; + data.apiurl = this.state.apiurl; } this.props.onClose(data); diff --git a/src/result/result-table.js b/src/result/result-table.js new file mode 100644 index 0000000..a38d160 --- /dev/null +++ b/src/result/result-table.js @@ -0,0 +1,257 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, {Component} from "react"; +import JSZip from 'jszip'; +import {Button} from "react-bootstrap"; +import FileSaver from 'file-saver'; +import AppDispatcher from "../common/app-dispatcher"; +import IconButton from "../common/icon-button"; +import Table from "../common/table"; +import TableColumn from "../common/table-column"; +import DeleteDialog from "../common/dialogs/delete-dialog"; +import EditResultDialog from "./edit-result"; +import ResultConfigDialog from "./result-configs-dialog"; +import NewResultDialog from "./new-result"; + +class ResultTable extends Component { + + constructor() { + super(); + + this.state = { + editResultsModal: false, + modalResultsData: {}, + modalResultsIndex: 0, + newResultModal: false, + filesToDownload: [], + zipfiles: false, + resultNodl: 0, + resultConfigsModal: false, + modalResultConfigs: {}, + modalResultConfigsIndex: 0, + } + } + + componentDidUpdate(prevProps, prevState) { + // check whether file data has been loaded + if (this.state.filesToDownload && this.state.filesToDownload.length > 0) { + if (this.props.files !== prevProps.files) { + if (!this.state.zipfiles) { + let fileToDownload = this.props.files.filter(file => file.id === this.state.filesToDownload[0]) + if (fileToDownload.length === 1 && fileToDownload[0].data) { + const blob = new Blob([fileToDownload[0].data], { type: fileToDownload[0].type }); + FileSaver.saveAs(blob, fileToDownload[0].name); + this.setState({ filesToDownload: [] }); + } + } else { // zip and save one or more files (download all button) + let filesToDownload = this.props.files.filter(file => this.state.filesToDownload.includes(file.id) && file.data); + if (filesToDownload.length === this.state.filesToDownload.length) { // all requested files have been loaded + var zip = new JSZip(); + filesToDownload.forEach(file => { + zip.file(file.name, file.data); + }); + let zipname = "result_" + this.state.resultNodl + "_" + (new Date()).toISOString(); + zip.generateAsync({ type: "blob" }).then(function (content) { + saveAs(content, zipname); + }); + this.setState({ filesToDownload: [] }); + } + } + } + } + } + + closeNewResultModal(data) { + this.setState({ newResultModal: false }); + if (data) { + data["scenarioID"] = this.props.scenario.id; + AppDispatcher.dispatch({ + type: 'results/start-add', + data, + token: this.props.sessionToken, + }); + } + } + + closeEditResultsModal() { + this.setState({ editResultsModal: false }); + } + + downloadResultData(param) { + let toDownload = []; + let zip = false; + + if (typeof (param) === 'object') { // download all files + toDownload = param.resultFileIDs; + zip = true; + this.setState({ filesToDownload: toDownload, zipfiles: zip, resultNodl: param.id }); + } else { // download one file + toDownload.push(param); + this.setState({ filesToDownload: toDownload, zipfiles: zip }); + } + + toDownload.forEach(fileid => { + AppDispatcher.dispatch({ + type: 'files/start-download', + data: fileid, + token: this.props.sessionToken + }); + }); + } + + closeDeleteResultsModal(confirmDelete) { + this.setState({ deleteResultsModal: false }); + + if (confirmDelete === false) { + return; + } + + AppDispatcher.dispatch({ + type: 'results/start-remove', + data: this.state.modalResultsData, + token: this.props.sessionToken, + }); + } + + + openResultConfigSnapshots(result) { + if (result.configSnapshots === null || result.configSnapshots === undefined) { + this.setState({ + modalResultConfigs: {"configs": []}, + modalResultConfigsIndex: result.id, + resultConfigsModal: true + }); + } else { + this.setState({ + modalResultConfigs: result.configSnapshots, + modalResultConfigsIndex: result.id, + resultConfigsModal: true + }); + } + } + + closeResultConfigSnapshots() { + this.setState({ resultConfigsModal: false }); + } + + modifyResultNoColumn(id, result) { + return + } + + render() { + const buttonStyle = { + marginLeft: '10px', + } + + const iconStyle = { + height: '30px', + width: '30px' + } + + return ( +
+ {/*Result table*/} +

Results + + this.setState({ newResultModal: true })} + icon='plus' + disabled={this.props.locked} + hidetooltip={this.props.locked} + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + +

+ + + this.modifyResultNoColumn(id, result)} + width={70} + /> + + + + this.downloadResultData(index)} + width={300} + /> + this.setState({ editResultsModal: true, modalResultsIndex: index })} + onDownloadAll={(index) => this.downloadResultData(this.props.results[index])} + onDelete={(index) => this.setState({ deleteResultsModal: true, modalResultsData: this.props.results[index], modalResultsIndex: index })} + locked={this.props.locked} + /> +
+ + + this.closeDeleteResultsModal(e)} + /> + + this.closeNewResultModal(data)} + /> +
+ ) + } +} + +export default ResultTable; diff --git a/src/router.js b/src/router.js index 7dcc072..98597ed 100644 --- a/src/router.js +++ b/src/router.js @@ -26,6 +26,7 @@ import Scenarios from './scenario/scenarios'; import Scenario from './scenario/scenario'; import Dashboard from './dashboard/dashboard' import InfrastructureComponents from './ic/ics'; +import InfrastructureComponent from './ic/ic'; import Users from './user/users'; import User from "./user/user"; import LoginComplete from './user/login-complete' @@ -46,6 +47,7 @@ class Root extends React.Component { + diff --git a/src/scenario/scenario-users-table.js b/src/scenario/scenario-users-table.js new file mode 100644 index 0000000..26eb06f --- /dev/null +++ b/src/scenario/scenario-users-table.js @@ -0,0 +1,162 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, {Component} from "react"; +import { Form, InputGroup} from "react-bootstrap"; +import {Redirect} from "react-router-dom"; +import Table from "../common/table"; +import TableColumn from "../common/table-column"; +import IconButton from "../common/icon-button"; +import DeleteDialog from "../common/dialogs/delete-dialog"; +import AppDispatcher from "../common/app-dispatcher"; + +class ScenarioUsersTable extends Component { + + constructor(props) { + super(props); + + this.state = { + userToAdd: '', + deleteUserName: '', + deleteUserModal: false, + goToScenarios: false + } + } + + onUserInputChange(e) { + this.setState({ userToAdd: e.target.value }); + } + + addUser() { + AppDispatcher.dispatch({ + type: 'scenarios/add-user', + data: this.props.scenario.id, + username: this.state.userToAdd, + token: this.props.sessionToken + }); + + this.setState({ userToAdd: '' }); + } + + closeDeleteUserModal() { + let scenarioID = this.props.scenario.id; + if (this.state.deleteUserName === this.props.currentUser.username) { + AppDispatcher.dispatch({ + type: 'scenarios/remove-user', + data: scenarioID, + username: this.state.deleteUserName, + token: this.props.sessionToken, + ownuser: true + }); + this.setState({ goToScenarios: true }); + } else { + AppDispatcher.dispatch({ + type: 'scenarios/remove-user', + data: scenarioID, + username: this.state.deleteUserName, + token: this.props.sessionToken, + ownuser: false + }); + } + this.setState({ deleteUserModal: false }); + } + + + render() { + if (this.state.goToScenarios) { + console.log("redirect to scenario overview") + return (); + } + + return ( +
+ {/*Scenario Users table*/} +

Users sharing this scenario

+ + {this.props.currentUser.role === "Admin" ? + + : <> + } + + + this.setState({ + deleteUserModal: true, + deleteUserName: this.props.scenario.users[index].username, + modalUserIndex: index + })} + locked={this.props.locked} + /> +
+ + + this.onUserInputChange(e)} + value={this.state.userToAdd} + type="text" + /> + + + this.addUser()} + icon='plus' + disabled={this.props.locked} + hidetooltip={this.props.locked} + /> + + + +
+
+ + this.closeDeleteUserModal(c)} + /> +
+ ) + } +} + +export default ScenarioUsersTable; + diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 1a42b66..ac618d7 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -17,144 +17,71 @@ import React from 'react'; import { Container } from 'flux/utils'; -import { Button, InputGroup, Form } from 'react-bootstrap'; -import FileSaver from 'file-saver'; +import AppDispatcher from '../common/app-dispatcher'; +import IconButton from '../common/icon-button'; +import IconToggleButton from '../common/icon-toggle-button'; import ScenarioStore from './scenario-store'; import ICStore from '../ic/ic-store'; import DashboardStore from '../dashboard/dashboard-store'; import ConfigStore from '../componentconfig/config-store'; import SignalStore from '../signal/signal-store' -import AppDispatcher from '../common/app-dispatcher'; - -import Icon from '../common/icon'; -import Table from '../common/table'; -import TableColumn from '../common/table-column'; -import IconButton from '../common/icon-button'; -import ImportConfigDialog from '../componentconfig/import-config'; -import ImportDashboardDialog from "../dashboard/import-dashboard"; -import NewDashboardDialog from "../dashboard/new-dashboard"; -import EditDashboardDialog from '../dashboard/edit-dashboard'; -import EditFilesDialog from '../file/edit-files' -import NewResultDialog from '../result/new-result'; -import EditResultDialog from '../result/edit-result'; -import ResultConfigDialog from '../result/result-configs-dialog'; - - -import ICAction from '../ic/ic-action'; -import DeleteDialog from '../common/dialogs/delete-dialog'; -import EditConfigDialog from "../componentconfig/edit-config"; -import EditSignalMappingDialog from "../signal/edit-signal-mapping"; import FileStore from "../file/file-store" import WidgetStore from "../widget/widget-store"; import ResultStore from "../result/result-store" -import { Redirect } from 'react-router-dom'; -import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; -var JSZip = require("jszip"); +import DashboardTable from '../dashboard/dashboard-table' +import ResultTable from "../result/result-table"; +import ConfigTable from "../componentconfig/config-table"; +import EditFilesDialog from '../file/edit-files' +import ScenarioUsersTable from "./scenario-users-table"; + class Scenario extends React.Component { + constructor(props) { + super(props); + + this.state = { + filesEditModal: false, + filesEditSaveState: [], + } + } + + static calculateState(prevState, props){ + let scenarioID = parseInt(props.match.params.scenario, 10) + + return{ + scenario: ScenarioStore.getState().find(s => s.id === scenarioID), + results: ResultStore.getState().filter(result => result.scenarioID === scenarioID), + sessionToken: localStorage.getItem("token"), + configs: ConfigStore.getState().filter(config => config.scenarioID === scenarioID), + widgets: WidgetStore.getState(), + dashboards: DashboardStore.getState().filter(dashb => dashb.scenarioID === scenarioID), + signals: SignalStore.getState(), + currentUser: JSON.parse(localStorage.getItem("currentUser")), + files: FileStore.getState().filter(file => file.scenarioID === scenarioID), + ics: ICStore.getState(), + } + } + static getStores() { return [ScenarioStore, ConfigStore, DashboardStore, ICStore, SignalStore, FileStore, WidgetStore, ResultStore]; } - static calculateState(prevState, props) { - if (prevState == null) { - prevState = {}; - } - - // get selected scenario - const sessionToken = localStorage.getItem("token"); - - const scenario = ScenarioStore.getState().find(s => s.id === parseInt(props.match.params.scenario, 10)); - if (scenario === undefined) { - AppDispatcher.dispatch({ - type: 'scenarios/start-load', - data: props.match.params.scenario, - token: sessionToken - }); - } - - // obtain all component configurations of a scenario - let configs = ConfigStore.getState().filter(config => config.scenarioID === parseInt(props.match.params.scenario, 10)); - let editConfigModal = prevState.editConfigModal || false; - let modalConfigData = (prevState.modalConfigData !== {} && prevState.modalConfigData !== undefined) ? prevState.modalConfigData : {}; - let modalConfigIndex = 0; - - if ((typeof prevState.configs !== "undefined") && (prevState.newConfig === true) && (configs.length !== prevState.configs.length)) { - let index = configs.length - 1; - editConfigModal = true; - modalConfigData = configs[index]; - modalConfigIndex = index; - } - - let results = ResultStore.getState().filter(result => result.scenarioID === parseInt(props.match.params.scenario, 10)); - - return { - scenario, - results, - sessionToken, - configs, - editConfigModal, - modalConfigData, - modalConfigIndex, - dashboards: DashboardStore.getState().filter(dashb => dashb.scenarioID === parseInt(props.match.params.scenario, 10)), - signals: SignalStore.getState(), - currentUser: JSON.parse(localStorage.getItem("currentUser")), - files: FileStore.getState().filter(file => file.scenarioID === parseInt(props.match.params.scenario, 10)), - - ics: ICStore.getState(), - ExternalICInUse: false, - - deleteConfigModal: false, - importConfigModal: false, - newConfig: prevState.newConfig || false, - selectedConfigs: prevState.selectedConfigs || [], - filesEditModal: prevState.filesEditModal || false, - filesEditSaveState: prevState.filesEditSaveState || [], - - editResultsModal: prevState.editResultsModal || false, - modalResultsData: {}, - modalResultsIndex: prevState.modalResultsIndex, - newResultModal: false, - filesToDownload: prevState.filesToDownload, - zipfiles: prevState.zipfiles || false, - resultNodl: prevState.resultNodl, - resultConfigsModal: false, - modalResultConfigs: {}, - modalResultConfigsIndex: 0, - - editOutputSignalsModal: prevState.editOutputSignalsModal || false, - editInputSignalsModal: prevState.editInputSignalsModal || false, - - newDashboardModal: false, - dashboardEditModal: prevState.dashboardEditModal || false, - deleteDashboardModal: false, - importDashboardModal: false, - modalDashboardData: {}, - - userToAdd: '', - deleteUserName: '', - deleteUserModal: false, - goToScenarios: false - } - } - componentDidMount() { - + let scenarioID = parseInt(this.props.match.params.scenario, 10) //load selected scenario AppDispatcher.dispatch({ type: 'scenarios/start-load', - data: parseInt(this.props.match.params.scenario, 10), + data: scenarioID, token: this.state.sessionToken }); - AppDispatcher.dispatch({ type: 'scenarios/start-load-users', - data: parseInt(this.props.match.params.scenario, 10), + data: scenarioID, token: this.state.sessionToken }); @@ -165,366 +92,10 @@ class Scenario extends React.Component { }); } - componentDidUpdate(prevProps, prevState) { - // check whether file data has been loaded - if (this.state.filesToDownload && this.state.filesToDownload.length > 0) { - if (this.state.files !== prevState.files) { - if (!this.state.zipfiles) { - let fileToDownload = FileStore.getState().filter(file => file.id === this.state.filesToDownload[0]) - if (fileToDownload.length === 1 && fileToDownload[0].data) { - const blob = new Blob([fileToDownload[0].data], { type: fileToDownload[0].type }); - FileSaver.saveAs(blob, fileToDownload[0].name); - this.setState({ filesToDownload: [] }); - } - } else { // zip and save one or more files (download all button) - let filesToDownload = FileStore.getState().filter(file => this.state.filesToDownload.includes(file.id) && file.data); - if (filesToDownload.length === this.state.filesToDownload.length) { // all requested files have been loaded - var zip = new JSZip(); - filesToDownload.forEach(file => { - zip.file(file.name, file.data); - }); - let zipname = "result_" + this.state.resultNodl + "_" + (new Date()).toISOString(); - zip.generateAsync({ type: "blob" }).then(function (content) { - saveAs(content, zipname); - }); - this.setState({ filesToDownload: [] }); - } - } - } - } - } - /* ############################################## - * User modification methods + * File modification methods ############################################## */ - onUserInputChange(e) { - this.setState({ userToAdd: e.target.value }); - } - - addUser() { - AppDispatcher.dispatch({ - type: 'scenarios/add-user', - data: this.state.scenario.id, - username: this.state.userToAdd, - token: this.state.sessionToken - }); - - this.setState({ userToAdd: '' }); - } - - closeDeleteUserModal() { - let scenarioID = this.state.scenario.id; - if (this.state.deleteUserName === this.state.currentUser.username) { - AppDispatcher.dispatch({ - type: 'scenarios/remove-user', - data: scenarioID, - username: this.state.deleteUserName, - token: this.state.sessionToken, - ownuser: true - }); - this.setState({ goToScenarios: true }); - } else { - AppDispatcher.dispatch({ - type: 'scenarios/remove-user', - data: scenarioID, - username: this.state.deleteUserName, - token: this.state.sessionToken, - ownuser: false - }); - } - this.setState({ deleteUserModal: false }); - } - - /* ############################################## - * Component Configuration modification methods - ############################################## */ - - addConfig() { - const config = { - scenarioID: this.state.scenario.id, - name: 'New Component Configuration', - icID: this.state.ics.length > 0 ? this.state.ics[0].id : null, - startParameters: {}, - }; - - AppDispatcher.dispatch({ - type: 'configs/start-add', - data: config, - token: this.state.sessionToken - }); - - this.setState({ newConfig: true }); - - } - - closeEditConfigModal(data) { - this.setState({ editConfigModal: false, newConfig: false }); - - if (data) { - AppDispatcher.dispatch({ - type: 'configs/start-edit', - data: data, - token: this.state.sessionToken, - }); - } - } - - closeDeleteConfigModal(confirmDelete) { - this.setState({ deleteConfigModal: false }); - - if (confirmDelete === false) { - return; - } - - AppDispatcher.dispatch({ - type: 'configs/start-remove', - data: this.state.modalConfigData, - token: this.state.sessionToken - }); - } - - importConfig(data) { - this.setState({ importConfigModal: false }); - - if (data == null) { - return; - } - - let newConfig = JSON.parse(JSON.stringify(data.config)) - - newConfig["scenarioID"] = this.state.scenario.id; - newConfig.name = data.name; - - AppDispatcher.dispatch({ - type: 'configs/start-add', - data: newConfig, - token: this.state.sessionToken - }); - } - - copyConfig(index) { - let config = JSON.parse(JSON.stringify(this.state.configs[index])); - - let signals = JSON.parse(JSON.stringify(SignalStore.getState().filter(s => s.configID === parseInt(config.id, 10)))); - signals.forEach((signal) => { - delete signal.configID; - delete signal.id; - }) - - // two separate lists for inputMapping and outputMapping - let inputSignals = signals.filter(s => s.direction === 'in'); - let outputSignals = signals.filter(s => s.direction === 'out'); - - // add signal mappings to config - config["inputMapping"] = inputSignals; - config["outputMapping"] = outputSignals; - - delete config.id; - delete config.scenarioID; - delete config.inputLength; - delete config.outputLength; - - return config; - } - - exportConfig(index) { - let config = this.copyConfig(index); - - // show save dialog - const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' }); - FileSaver.saveAs(blob, 'config-' + config.name + '.json'); - } - - duplicateConfig(index) { - let newConfig = this.copyConfig(index); - newConfig["scenarioID"] = this.state.scenario.id; - newConfig.name = newConfig.name + '_copy'; - - AppDispatcher.dispatch({ - type: 'configs/start-add', - data: newConfig, - token: this.state.sessionToken - }); - } - - onConfigChecked(index, event) { - const selectedConfigs = Object.assign([], this.state.selectedConfigs); - for (let key in selectedConfigs) { - if (selectedConfigs[key] === index) { - // update existing entry - if (event.target.checked) { - return; - } - - selectedConfigs.splice(key, 1); - - this.setState({ selectedConfigs: selectedConfigs }); - return; - } - } - - // add new entry - if (event.target.checked === false) { - return; - } - - selectedConfigs.push(index); - this.setState({ selectedConfigs: selectedConfigs }); - } - - usesExternalIC(index) { - let icID = this.state.configs[index].icID; - - let ic = null; - for (let component of this.state.ics) { - if (component.id === icID) { - ic = component; - } - } - - if (ic == null) { - return false; - } - - if (ic.managedexternally === true) { - this.setState({ ExternalICInUse: true }) - return true - } - - return false - } - - getICName(icID) { - for (let ic of this.state.ics) { - if (ic.id === icID) { - return ic.name || ic.uuid; - } - } - } - - /* ############################################## - * Dashboard modification methods - ############################################## */ - - closeNewDashboardModal(data) { - this.setState({ newDashboardModal: false }); - if (data) { - // TODO: 'newDashboard' not used, check this - let newDashboard = data; - // add default grid value and scenarioID - newDashboard["grid"] = 15; - newDashboard["scenarioID"] = this.state.scenario.id; - - AppDispatcher.dispatch({ - type: 'dashboards/start-add', - data, - token: this.state.sessionToken, - }); - } - } - - closeEditDashboardModal(data) { - this.setState({ dashboardEditModal: false }); - - let editDashboard = this.state.modalDashboardData; - - if (data != null) { - editDashboard.name = data.name; - AppDispatcher.dispatch({ - type: 'dashboards/start-edit', - data: editDashboard, - token: this.state.sessionToken - }); - } - } - - closeDeleteDashboardModal(confirmDelete) { - this.setState({ deleteDashboardModal: false }); - - if (confirmDelete === false) { - return; - } - - AppDispatcher.dispatch({ - type: 'dashboards/start-remove', - data: this.state.modalDashboardData, - token: this.state.sessionToken, - }); - } - - closeImportDashboardModal(data) { - this.setState({ importDashboardModal: false }); - - if (data) { - let newDashboard = JSON.parse(JSON.stringify(data)); - newDashboard["scenarioID"] = this.state.scenario.id; - - AppDispatcher.dispatch({ - type: 'dashboards/start-add', - data: newDashboard, - token: this.state.sessionToken, - }); - } - } - - copyDashboard(index) { - let dashboard = JSON.parse(JSON.stringify(this.state.dashboards[index])); - - let widgets = JSON.parse(JSON.stringify(WidgetStore.getState().filter(w => w.dashboardID === parseInt(dashboard.id, 10)))); - widgets.forEach((widget) => { - delete widget.dashboardID; - delete widget.id; - }) - dashboard["widgets"] = widgets; - delete dashboard.scenarioID; - delete dashboard.id; - - return dashboard; - } - - exportDashboard(index) { - let dashboard = this.copyDashboard(index); - - // show save dialog - const blob = new Blob([JSON.stringify(dashboard, null, 2)], { type: 'application/json' }); - FileSaver.saveAs(blob, 'dashboard - ' + dashboard.name + '.json'); - } - - duplicateDashboard(index) { - let newDashboard = this.copyDashboard(index); - newDashboard.scenarioID = this.state.scenario.id; - newDashboard.name = newDashboard.name + '_copy'; - - AppDispatcher.dispatch({ - type: 'dashboards/start-add', - data: newDashboard, - token: this.state.sessionToken, - }); - } - - /* ############################################## - * Signal modification methods - ############################################## */ - - closeEditSignalsModal(direction) { - - // reload the config - AppDispatcher.dispatch({ - type: 'configs/start-load', - data: this.state.modalConfigData.id, - token: this.state.sessionToken - }); - - if (direction === "in") { - this.setState({ editInputSignalsModal: false }); - } else if (direction === "out") { - this.setState({ editOutputSignalsModal: false }); - } - - - } - onEditFiles() { let tempFiles = []; this.state.files.forEach(file => { @@ -538,213 +109,76 @@ class Scenario extends React.Component { closeEditFiles() { this.setState({ filesEditModal: false }); - // TODO do we need this if the dispatches happen in the dialog? - } - - signalsAutoConf(index) { - let componentConfig = this.state.configs[index]; - // determine apiurl of infrastructure component - let ic = this.state.ics.find(ic => ic.id === componentConfig.icID) - if (!ic.type.includes("villas-node")) { - let message = "Cannot autoconfigure signals for IC type " + ic.type + " of category " + ic.category + ". This is only possible for gateway ICs of type 'VILLASnode'." - console.warn(message); - - const SIGNAL_AUTOCONF_WARN_NOTIFICATION = { - title: 'Failed to load signal config for IC ' + ic.name, - message: message, - level: 'warning' - }; - NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_WARN_NOTIFICATION); - return; - } - - let splitWebsocketURL = ic.websocketurl.split("/") - - AppDispatcher.dispatch({ - type: 'signals/start-autoconfig', - url: ic.apiurl + "/nodes", - socketname: splitWebsocketURL[splitWebsocketURL.length - 1], - token: this.state.sessionToken, - configID: componentConfig.id - }); - - } - - uuidv4() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - // eslint-disable-next-line - var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); } /* ############################################## - * File modification methods + * Change locked state of scenario ############################################## */ - getListOfFiles(files, fileIDs) { - let fileList = []; - - for (let id of fileIDs) { - for (let file of files) { - if (file.id === id) { - fileList.push(file.name) - } - } - } - - return fileList.join(';'); - } - - /* ############################################## - * Result modification methods - ############################################## */ - - closeNewResultModal(data) { - this.setState({ newResultModal: false }); - if (data) { - data["scenarioID"] = this.state.scenario.id; - AppDispatcher.dispatch({ - type: 'results/start-add', - data, - token: this.state.sessionToken, - }); - } - } - - closeEditResultsModal() { - this.setState({ editResultsModal: false }); - } - - downloadResultData(param) { - let toDownload = []; - let zip = false; - - if (typeof (param) === 'object') { // download all files - toDownload = param.resultFileIDs; - zip = true; - this.setState({ filesToDownload: toDownload, zipfiles: zip, resultNodl: param.id }); - } else { // download one file - toDownload.push(param); - this.setState({ filesToDownload: toDownload, zipfiles: zip }); - } - - toDownload.forEach(fileid => { - AppDispatcher.dispatch({ - type: 'files/start-download', - data: fileid, - token: this.state.sessionToken - }); - }); - } - - closeDeleteResultsModal(confirmDelete) { - this.setState({ deleteResultsModal: false }); - - if (confirmDelete === false) { - return; - } + onChangeLock() { + let data = {}; + data.id = this.state.scenario.id; + data.isLocked = !this.state.scenario.isLocked; AppDispatcher.dispatch({ - type: 'results/start-remove', - data: this.state.modalResultsData, - token: this.state.sessionToken, + type: 'scenarios/start-edit', + data, + token: this.state.sessionToken }); } - openResultConfigSnaphots(result) { - if (result.configSnapshots === null || result.configSnapshots === undefined) { - this.setState({ - modalResultConfigs: {"configs": []}, - modalResultConfigsIndex: result.id, - resultConfigsModal: true - }); - } else { - this.setState({ - modalResultConfigs: result.configSnapshots, - modalResultConfigsIndex: result.id, - resultConfigsModal: true - }); - } - } - - closeResultConfigSnapshots() { - this.setState({ resultConfigsModal: false }); - } - - modifyResultNoColumn(id, result) { - return - } - - startPintura(configIndex) { - let config = this.state.configs[configIndex]; - - // get xml / CIM file - let files = [] - for (let id of config.fileIDs) { - for (let file of this.state.files) { - if (file.id === id && ['xml'].some(e => file.type.includes(e))) { - files.push(file); - } - } - } - - if (files.length > 1) { - // more than one CIM file... - console.warn("There is more than one CIM file selected in this component configuration. I will open them all in a separate tab.") - } - - let baseURL = 'aaa.bbb.ccc.ddd/api/v2/files/' - for (let file of files) { - // endpoint param serves for download and upload of CIM file, token is required for authentication - let params = { - token: this.state.sessionToken, - endpoint: baseURL + String(file.id), - } - - // TODO start Pintura for editing CIM/ XML file from here - console.warn("Starting Pintura... and nothing happens so far :-) ", params) - } - } - - /* ############################################## * Render method ############################################## */ render() { - if (this.state.goToScenarios) { - console.log("redirect to scenario overview") - return (); - } - - const altButtonStyle = { + const buttonStyle = { marginLeft: '10px', } - const tableHeadingStyle = { - paddingTop: '30px' - } - const iconStyle = { height: '30px', width: '30px' } + const tableHeadingStyle = { + paddingTop: '30px' + } + if (this.state.scenario === undefined) { return

Loading Scenario...

; } + let tooltip = this.state.scenario.isLocked ? "View files of scenario" : "Add, edit or delete files of scenario"; + return
-

{this.state.scenario.name}

+

+ {this.state.scenario.name} + + this.onChangeLock()} + checked={this.state.scenario.isLocked} + checkedIcon='lock' + uncheckedIcon='lock-open' + tooltipChecked='Scenario is locked, cannot be edited' + tooltipUnchecked='Scenario is unlocked, can be edited' + disabled={this.state.currentUser.role !== "Admin"} + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + +

- {/*Component Configurations table*/} -

Component Configurations - - this.addConfig()} - icon='plus' - /> - this.setState({ importConfigModal: true })} - icon='upload' - /> - -

- - !this.usesExternalIC(index)} - onChecked={(index, event) => this.onConfigChecked(index, event)} - width={20} - /> - {this.state.currentUser.role === "Admin" ? - - : <> - } - - this.setState({ editOutputSignalsModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })} - width={150} - /> - this.setState({ editInputSignalsModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })} - width={150} - /> - this.signalsAutoConf(index)} - width={150} - /> - this.getICName(icID)} - width={300} - /> - this.setState({ editConfigModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })} - onDelete={(index) => this.setState({ deleteConfigModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })} - onExport={index => this.exportConfig(index)} - onDuplicate={index => this.duplicateConfig(index)} - /> -
- - {this.state.ExternalICInUse ? -
- this.copyConfig(index)} - token = {this.state.sessionToken} - actions={[ - { id: '0', title: 'Start', data: { action: 'start' } }, - { id: '1', title: 'Stop', data: { action: 'stop' } }, - { id: '2', title: 'Pause', data: { action: 'pause' } }, - { id: '3', title: 'Resume', data: { action: 'resume' } } - ]} /> -
- :
- } - -
- - this.closeEditConfigModal(data)} - config={this.state.modalConfigData} - ics={this.state.ics} + - this.importConfig(data)} ics={this.state.ics} - /> - this.closeDeleteConfigModal(c)} - /> - this.closeEditSignalsModal(direction)} - direction="Output" signals={this.state.signals} - configID={this.state.modalConfigData.id} + scenario={this.state.scenario} sessionToken={this.state.sessionToken} + currentUser={this.state.currentUser} + tableHeadingStyle={tableHeadingStyle} + locked={this.state.scenario.isLocked} /> - this.closeEditSignalsModal(direction)} - direction="Input" - signals={this.state.signals} - configID={this.state.modalConfigData.id} + + - {/*Dashboard table*/} -

Dashboards - - this.setState({ newDashboardModal: true })} - icon='plus' - /> - this.setState({ importDashboardModal: true })} - icon='upload' - /> - -

- - {this.state.currentUser.role === "Admin" ? - - : <> - } - - - - this.setState({ dashboardEditModal: true, modalDashboardData: this.state.dashboards[index] })} - onDelete={(index) => this.setState({ deleteDashboardModal: true, modalDashboardData: this.state.dashboards[index], modalDashboardIndex: index })} - onExport={index => this.exportDashboard(index)} - onDuplicate={index => this.duplicateDashboard(index)} - /> -
- - this.closeNewDashboardModal(data)} - /> - this.closeEditDashboardModal(data)} - /> - this.closeImportDashboardModal(data)} - /> - this.closeDeleteDashboardModal(e)} - /> - - {/*Result table*/} -

Results - - this.setState({ newResultModal: true })} - icon='plus' - /> - -

- - - this.modifyResultNoColumn(id, result)} - width={70} - /> - - - - this.downloadResultData(index)} - width={300} - /> - this.setState({ editResultsModal: true, modalResultsIndex: index })} - onDownloadAll={(index) => this.downloadResultData(this.state.results[index])} - onDelete={(index) => this.setState({ deleteResultsModal: true, modalResultsData: this.state.results[index], modalResultsIndex: index })} - /> -
- - - this.closeDeleteResultsModal(e)} - /> - - this.closeNewResultModal(data)} + files={this.state.files} + scenario={this.state.scenario} + sessionToken={this.state.sessionToken} + tableHeadingStyle={tableHeadingStyle} + locked={this.state.scenario.isLocked} /> - {/*Scenario Users table*/} -

Users sharing this scenario

- - {this.state.currentUser.role === "Admin" ? - - : <> - } - - - this.setState({ - deleteUserModal: true, - deleteUserName: this.state.scenario.users[index].username, - modalUserIndex: index - })} - /> -
- - - this.onUserInputChange(e)} - value={this.state.userToAdd} - type="text" - /> - - - - - - -
-
- - this.closeDeleteUserModal(c)} + -
; + +
} } diff --git a/src/scenario/scenarios.js b/src/scenario/scenarios.js index 4b32696..89b52d9 100644 --- a/src/scenario/scenarios.js +++ b/src/scenario/scenarios.js @@ -73,7 +73,7 @@ class Scenarios extends Component { } closeNewModal(data) { - if(data) { + if (data) { AppDispatcher.dispatch({ type: 'scenarios/start-add', data: data, @@ -218,7 +218,7 @@ class Scenarios extends Component { jsonObj["configs"] = this.getConfigs(scenario.id); jsonObj["dashboards"] = this.getDashboards(scenario.id); - if(jsonObj) { + if (jsonObj) { AppDispatcher.dispatch({ type: 'scenarios/start-add', data: jsonObj, @@ -227,68 +227,99 @@ class Scenarios extends Component { } } - modifyRunningColumn(running){ - return + isLocked(index) { + return this.state.scenarios[index].isLocked; + } + + onLock(index) { + let data = {}; + data.id = this.state.scenarios[index].id; + data.isLocked = !this.state.scenarios[index].isLocked; + + AppDispatcher.dispatch({ + type: 'scenarios/start-edit', + data, + token: this.state.sessionToken + }); } render() { + const buttonStyle = { + marginLeft: '10px', + } + + const iconStyle = { + height: '30px', + width: '30px' + } + return
-

Scenarios +

Scenarios - this.setState({ newModal: true })} - icon='plus' - /> - this.setState({ importModal: true })} - icon='upload' - /> - -

- - - {this.state.currentUser.role === "Admin" ? - - : <> - } - this.setState({ newModal: true })} + icon='plus' + buttonStyle={buttonStyle} + iconStyle={iconStyle} /> - this.modifyRunningColumn(running)} + this.setState({ importModal: true })} + icon='upload' + buttonStyle={buttonStyle} + iconStyle={iconStyle} /> + + + +
+ {this.state.currentUser.role === "Admin" ? this.setState({ editModal: true, modalScenario: this.state.scenarios[index] })} - onDelete={index => this.setState({ deleteModal: true, modalScenario: this.state.scenarios[index] })} - onExport={index => this.exportScenario(index)} - onDuplicate={index => this.duplicateScenario(index)} + title='ID' + dataKey='id' /> -
+ : <> + } + + {this.state.currentUser.role === "Admin" ? + this.onLock(index)} + isLocked={index => this.isLocked(index)} + /> + : <> + } + this.setState({ editModal: true, modalScenario: this.state.scenarios[index] })} + onDelete={index => this.setState({ deleteModal: true, modalScenario: this.state.scenarios[index] })} + onExport={index => this.exportScenario(index)} + onDuplicate={index => this.duplicateScenario(index)} + isLocked={index => this.isLocked(index)} + /> + - this.closeNewModal(data)} /> - this.closeEditModal(data)} scenario={this.state.modalScenario} /> - this.closeImportModal(data)} nodes={this.state.nodes} /> + this.closeNewModal(data)} /> + this.closeEditModal(data)} scenario={this.state.modalScenario} /> + this.closeImportModal(data)} nodes={this.state.nodes} /> - this.closeDeleteModal(e)} /> -
; + this.closeDeleteModal(e)} /> +
; } } diff --git a/src/user/login.js b/src/user/login.js index f7dcc17..a91fa89 100644 --- a/src/user/login.js +++ b/src/user/login.js @@ -15,7 +15,7 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { Component } from 'react'; +import React from 'react'; import { Container } from 'flux/utils'; import { NavbarBrand } from 'react-bootstrap'; import NotificationSystem from 'react-notification-system'; @@ -29,15 +29,10 @@ import AppDispatcher from '../common/app-dispatcher'; import branding from '../branding/branding'; -class Login extends Component { +class Login extends React.Component { constructor(props) { super(props); - // Load config in case the user goes directly to /login - // otherwise it will be loaded in app constructor - AppDispatcher.dispatch({ - type: 'config/load', - }); } static getStores() { @@ -57,6 +52,12 @@ class Login extends Component { componentDidMount() { NotificationsDataManager.setSystem(this.refs.notificationSystem); + + // load config in case the user goes directly to /login + // otherwise it will be loaded in app constructor + AppDispatcher.dispatch({ + type: 'config/load', + }); } render() { diff --git a/src/user/logout.js b/src/user/logout.js index 7ffce70..36a49b5 100644 --- a/src/user/logout.js +++ b/src/user/logout.js @@ -26,11 +26,7 @@ class Logout extends React.Component { type: 'users/logout' }); - // The Login Store is deleted automatically - - // discard login token and current User - localStorage.setItem('token', ''); - localStorage.setItem('currentUser', ''); + // The Login Store and local storage are deleted automatically } render() { @@ -40,4 +36,4 @@ class Logout extends React.Component { } } -export default Logout; \ No newline at end of file +export default Logout; diff --git a/src/user/users.js b/src/user/users.js index 8c229b9..5d97e68 100644 --- a/src/user/users.js +++ b/src/user/users.js @@ -119,7 +119,7 @@ class Users extends Component {

Users this.setState({ newModal: true })} icon='plus' diff --git a/src/widget/edit-widget/edit-widget-color-control.js b/src/widget/edit-widget/edit-widget-color-control.js index ada958f..6fd82f7 100644 --- a/src/widget/edit-widget/edit-widget-color-control.js +++ b/src/widget/edit-widget/edit-widget-color-control.js @@ -16,7 +16,7 @@ ******************************************************************************/ import React, { Component } from 'react'; -import { Form, OverlayTrigger, Tooltip, Button } from 'react-bootstrap'; +import { Form, OverlayTrigger, Tooltip, Button, Col } from 'react-bootstrap'; import ColorPicker from './color-picker' import Icon from "../../common/icon"; @@ -77,8 +77,8 @@ class EditWidgetColorControl extends Component { let style = { backgroundColor: color, opacity: opacity, - width: '260px', - height: '40px' + width: '80px', + height: '40px', } let tooltipText = "Change color and opacity"; @@ -87,19 +87,23 @@ class EditWidgetColorControl extends Component { } - return - {this.props.label} + return ( + + {this.props.label} + -
- {tooltipText} } > - - -
- - this.closeEditModal(data)} widget={this.state.widget} controlId={this.props.controlId} disableOpacity={this.props.disableOpacity}/> -
; + +
+ {tooltipText} } > + + +
+ this.closeEditModal(data)} widget={this.state.widget} controlId={this.props.controlId} disableOpacity={this.props.disableOpacity}/> +
+ + ); } } diff --git a/src/widget/edit-widget/edit-widget.js b/src/widget/edit-widget/edit-widget.js index e7792a8..6ceef7b 100644 --- a/src/widget/edit-widget/edit-widget.js +++ b/src/widget/edit-widget/edit-widget.js @@ -174,6 +174,7 @@ class EditWidgetDialog extends React.Component { onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid} + size={'sm'} >
{ controls || '' } diff --git a/src/widget/widget-context-menu.js b/src/widget/widget-context-menu.js index b869966..2bb64e6 100644 --- a/src/widget/widget-context-menu.js +++ b/src/widget/widget-context-menu.js @@ -17,7 +17,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Menu, Item, Separator, MenuProvider } from 'react-contexify'; +import { Menu, Item, Separator, contextMenu } from 'react-contexify'; import Widget from './widget'; class WidgetContextMenu extends React.Component { @@ -93,45 +93,64 @@ class WidgetContextMenu extends React.Component { } }; + showMenu = e => { + let index = this.props.index + if (this.props.editing){ + contextMenu.show({ + event: e, + id: 'widgetMenu' + index, + position: { + x: 'inherit', + y: 'inherit', + } + }) + } + else { + contextMenu.show({ + event: e, + id: 'widgetMenu' + index, + }) + } + } + render() { const isLocked = this.props.widget.locked; - const ContextMenu = () => ( - - Edit - Duplicate - Delete - + let dim = { + width: '100%', + height: '100%' + }; - Move above - Move to front - Move underneath - Move to back + return ( - +
+ - Lock - Unlock -
- ); + + Edit + Duplicate + Delete - let dim = { - width: '100%', - height: '100%' - }; + - return
- - - - -
+ Move above + Move to front + Move underneath + Move to back + + + + Lock + Unlock +
+

+ ); } }