diff --git a/README.md b/README.md index 47bf2a7..1d14bf8 100644 --- a/README.md +++ b/README.md @@ -91,3 +91,4 @@ To analyze the code and find problems according to the given rules, described in ├── package.json └── tsconfig.json ``` + diff --git a/package-lock.json b/package-lock.json index e0e4135..33d6a2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "@reduxjs/toolkit": "^1.9.5", + "@types/js-cookie": "^3.0.6", "axios": "^1.4.0", "classnames": "^2.3.2", "nanoid": "^4.0.2", @@ -125,81 +126,17 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dependencies": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { "version": "7.22.9", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", @@ -246,13 +183,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", "dependencies": { - "@babel/types": "^7.22.10", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -387,20 +324,20 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -542,17 +479,17 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -592,13 +529,14 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -669,9 +607,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz", - "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2008,32 +1946,32 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", - "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", - "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.11", - "@babel/types": "^7.22.11", - "debug": "^4.1.0", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -2049,12 +1987,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", - "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2610,13 +2548,13 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -2631,9 +2569,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -2654,9 +2592,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -3223,6 +3161,11 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==" + }, "node_modules/@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -4084,11 +4027,11 @@ } }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -4176,13 +4119,13 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -4190,7 +4133,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -4673,9 +4616,9 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, "engines": { "node": ">= 0.6" @@ -5898,17 +5841,17 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -6135,9 +6078,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -8272,9 +8215,9 @@ } }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -8290,9 +8233,9 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -8376,9 +8319,9 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -8539,9 +8482,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -9547,9 +9490,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "engines": { "node": ">=0.10.0" } @@ -10576,9 +10519,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, "dependencies": { "colorette": "^2.0.10", @@ -10973,63 +10916,12 @@ } }, "@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "requires": { - "@babel/highlight": "^7.22.10", - "chalk": "^2.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" } }, "@babel/compat-data": { @@ -11067,13 +10959,13 @@ } }, "@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", "requires": { - "@babel/types": "^7.22.10", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" } }, @@ -11178,17 +11070,17 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -11285,14 +11177,14 @@ } }, "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==" }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.22.5", @@ -11320,13 +11212,14 @@ } }, "@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "requires": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "dependencies": { "ansi-styles": { @@ -11381,9 +11274,9 @@ } }, "@babel/parser": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz", - "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==" + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.22.5", @@ -12245,29 +12138,29 @@ } }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" } }, "@babel/traverse": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz", - "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==", - "requires": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "requires": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.11", - "@babel/types": "^7.22.11", - "debug": "^4.1.0", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { @@ -12279,12 +12172,12 @@ } }, "@babel/types": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz", - "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -12594,13 +12487,13 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } }, "@jridgewell/resolve-uri": { @@ -12609,9 +12502,9 @@ "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" }, "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/source-map": { "version": "0.3.5", @@ -12629,9 +12522,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -13030,6 +12923,11 @@ "@types/istanbul-lib-report": "*" } }, + "@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==" + }, "@types/json-schema": { "version": "7.0.12", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", @@ -13687,11 +13585,11 @@ "dev": true }, "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "requires": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -13760,13 +13658,13 @@ "devOptional": true }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -13774,7 +13672,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -14120,9 +14018,9 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true }, "cookie-signature": { @@ -15014,17 +14912,17 @@ } }, "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -15224,9 +15122,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "for-each": { "version": "0.3.3", @@ -16750,19 +16648,19 @@ } }, "postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "requires": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "dependencies": { "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" } } }, @@ -16919,9 +16817,9 @@ "dev": true }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "requires": { "bytes": "3.1.2", @@ -17647,9 +17545,9 @@ "dev": true }, "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==" }, "source-map-support": { "version": "0.5.21", @@ -18397,9 +18295,9 @@ } }, "webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, "requires": { "colorette": "^2.0.10", diff --git a/package.json b/package.json index 940d82c..1265a7e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "flat": true, "dependencies": { "@reduxjs/toolkit": "^1.9.5", + "@types/js-cookie": "^3.0.6", "axios": "^1.4.0", "classnames": "^2.3.2", "nanoid": "^4.0.2", diff --git a/src/@types/png.d.ts b/src/@types/png.d.ts new file mode 100644 index 0000000..1c59232 --- /dev/null +++ b/src/@types/png.d.ts @@ -0,0 +1,4 @@ +declare module '*.png' { + const value: string; + export default value; +} diff --git a/src/api/requests/authenticate.ts b/src/api/requests/authenticate.ts new file mode 100644 index 0000000..4dee5e7 --- /dev/null +++ b/src/api/requests/authenticate.ts @@ -0,0 +1,26 @@ +import { type ScAddr } from 'ts-sc-client'; + +import { scUtils } from '@api'; +import { Action } from '@api/sc/actions/Action'; + +interface IRequest { + login: string; + password: string; +} + +export const authenticateUser = async (req: IRequest): Promise => { + const action = new Action('action_authorise_user'); + + const loginLink = await scUtils.createLink(req.login); + const passwordLink = await scUtils.createLink(req.password); + + if (loginLink && passwordLink) { + action.addArgs(loginLink, passwordLink); + } + + const resp = await action.initiate(); + + if (!resp) throw new Error('unauthenticated'); + + return resp; +}; diff --git a/src/assets/images/DevModeOFF.svg b/src/assets/images/DevModeOFF.svg new file mode 100644 index 0000000..de2af80 --- /dev/null +++ b/src/assets/images/DevModeOFF.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/DevModeON.svg b/src/assets/images/DevModeON.svg new file mode 100644 index 0000000..4f9141f --- /dev/null +++ b/src/assets/images/DevModeON.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/UserIcon.svg b/src/assets/images/UserIcon.svg new file mode 100644 index 0000000..9c0829e --- /dev/null +++ b/src/assets/images/UserIcon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/images/authPage.png b/src/assets/images/authPage.png new file mode 100644 index 0000000..5631e1e Binary files /dev/null and b/src/assets/images/authPage.png differ diff --git a/src/assets/images/goBackDark.svg b/src/assets/images/goBackDark.svg new file mode 100644 index 0000000..445ad6b --- /dev/null +++ b/src/assets/images/goBackDark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/styles/core/base.scss b/src/assets/styles/core/base.scss index f6f99f5..3004644 100644 --- a/src/assets/styles/core/base.scss +++ b/src/assets/styles/core/base.scss @@ -6,6 +6,11 @@ body, height: 100%; } +#root { + width: 100%; + height: 100%; +} + #content { display: flex; flex-direction: column; diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index 7d1a576..9e82f56 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -2,6 +2,7 @@ import { Expandable, useBooleanState } from 'ostis-ui-lib'; import { FC, ReactNode } from 'react'; import ChevronDown from '@assets/images/chevronDown.svg'; import { IconButton } from '@components/IconButton'; +import { Tooltip } from '@components/ToolTip/ToolTip'; import { ChevronDownWrapper, ContentWrapper, HeaderWrapper, Icon, LeftContent } from './styled'; @@ -13,6 +14,7 @@ interface IProps { className?: string; expanded?: boolean; isAutoControl?: boolean; + systemId: string; onRightClick?: () => void; onToggle?: (expanded: boolean) => void; } @@ -27,6 +29,7 @@ export const Accordion: FC = ({ expanded: outerExpanded = true, isAutoControl = true, onRightClick, + systemId, }) => { const [expanded, , , onToggleExpanded] = useBooleanState(outerExpanded, { updateable: true, @@ -50,13 +53,15 @@ export const Accordion: FC = ({ return (
- - {leftIcon && {leftIcon}} - {header} - - - - + + + {leftIcon && {leftIcon}} + {header} + + + + + {rightIcon && ( {rightIcon} diff --git a/src/components/ConfirmAction/ConfirmAction.tsx b/src/components/ConfirmAction/ConfirmAction.tsx index bf5305c..9993bb8 100644 --- a/src/components/ConfirmAction/ConfirmAction.tsx +++ b/src/components/ConfirmAction/ConfirmAction.tsx @@ -11,7 +11,13 @@ interface IProps { className?: string; } -export const ConfirmAction: FC = ({ onComplete, onClose, title, content, completeBtnText = 'Подтвердить' }) => { +export const ConfirmAction: FC = ({ + onComplete, + onClose, + title, + content, + completeBtnText = 'Подтвердить', +}) => { const onCompleteFunc = () => { onComplete(); onClose(); diff --git a/src/components/DecompositionPanel/DecompositionPanel.tsx b/src/components/DecompositionPanel/DecompositionPanel.tsx new file mode 100644 index 0000000..0ed5fb7 --- /dev/null +++ b/src/components/DecompositionPanel/DecompositionPanel.tsx @@ -0,0 +1,89 @@ +import { ChangeEvent, FC, KeyboardEvent, useRef } from 'react'; +import { useClickOutside } from 'ostis-ui-lib'; + +import { NavigationList } from './components/NavigationList'; +import { Skeleton } from './components/Skeleton'; +import { TextAreaItem } from './components/TextAreaItem'; +import { Nav } from './styled'; +import { ITransformedDecomposition } from './types'; +import { useDecompositionContext } from 'ostis-ui-lib'; + +const emptyArray: ITransformedDecomposition[] = []; + +interface IProps { + className?: string; + editable?: boolean; + deleteable?: boolean; +} + +export const DecompositionPanel: FC = ({ + className, + editable = false, + deleteable = false, +}) => { + const { + isMenuListLoading, + menuList, + isAddInputShow, + setIsAddInputShow, + addInputValue, + setAddInputValue, + onAdd, + onDelete, + } = useDecompositionContext(); + + const wrapperAddInputRef = useRef(null); + + const onChangeAddInput = (e: ChangeEvent) => { + setAddInputValue(e.target.value); + }; + + const onTextAreaAddKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter') { + saveAddItemValue(); + } + + if (e.key === 'Escape') { + setIsAddInputShow(false); + setAddInputValue(''); + } + }; + + const saveAddItemValue = () => { + if (!menuList) return; + + if (addInputValue.trim()) onAdd(menuList.id, addInputValue, Math.random()); + + setIsAddInputShow(false); + setAddInputValue(''); + onDelete(1); + }; + + useClickOutside(wrapperAddInputRef, saveAddItemValue); + + return ( +
+ +
+ ); +}; diff --git a/src/components/DecompositionPanel/components/EditTextarea/EditTextarea.tsx b/src/components/DecompositionPanel/components/EditTextarea/EditTextarea.tsx new file mode 100644 index 0000000..2b0c7d8 --- /dev/null +++ b/src/components/DecompositionPanel/components/EditTextarea/EditTextarea.tsx @@ -0,0 +1,52 @@ +import { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react'; +import { useClickOutside } from 'ostis-ui-lib'; + +import { StyledTextarea } from './styled'; + +interface IProps { + onClose: () => void; + onSave: (value: string) => void; + defaultValue: string; +} + +export const EditTextarea = ({ defaultValue, onClose, onSave }: IProps) => { + const [editInputValue, setEditInputValue] = useState(defaultValue); + + const wrapperEditInputRef = useRef(null); + + const saveEditItemValue = () => { + if (editInputValue.trim()) onSave(editInputValue); + + onClose(); + }; + + const onTextAreaEditKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter') { + saveEditItemValue(); + } + + if (e.key === 'Escape') onClose(); + }; + + const onChangeEditInput = (e: ChangeEvent) => { + setEditInputValue(e.target.value); + }; + + useEffect(() => { + if (wrapperEditInputRef.current) { + wrapperEditInputRef.current.selectionStart = wrapperEditInputRef.current.value.length; + } + }, []); + + useClickOutside(wrapperEditInputRef, saveEditItemValue); + + return ( + + ); +}; diff --git a/src/components/DecompositionPanel/components/EditTextarea/index.tsx b/src/components/DecompositionPanel/components/EditTextarea/index.tsx new file mode 100644 index 0000000..99bd6d4 --- /dev/null +++ b/src/components/DecompositionPanel/components/EditTextarea/index.tsx @@ -0,0 +1 @@ +export * from './EditTextarea'; diff --git a/src/components/DecompositionPanel/components/EditTextarea/styled.ts b/src/components/DecompositionPanel/components/EditTextarea/styled.ts new file mode 100644 index 0000000..8883a31 --- /dev/null +++ b/src/components/DecompositionPanel/components/EditTextarea/styled.ts @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +import { Textarea } from 'ostis-ui-lib'; + +export const StyledTextarea = styled(Textarea)` + height: 28px; + + overflow: hidden; +`; diff --git a/src/components/DecompositionPanel/components/NavigationList/NavigationList.tsx b/src/components/DecompositionPanel/components/NavigationList/NavigationList.tsx new file mode 100644 index 0000000..0d31051 --- /dev/null +++ b/src/components/DecompositionPanel/components/NavigationList/NavigationList.tsx @@ -0,0 +1,215 @@ +import { + ChangeEvent, + KeyboardEvent, + memo, + PropsWithChildren, + ReactNode, + useEffect, + useRef, + useState, +} from 'react'; +import { useDecompositionContext } from 'ostis-ui-lib'; +import { ScLangText } from 'ostis-ui-lib'; +import { useClickOutside } from 'ostis-ui-lib'; +import { Tooltip } from '@components/ToolTip/ToolTip'; + +import { ITransformedDecomposition } from '../../types'; +import { EditTextarea } from '../EditTextarea'; +import { Options } from '../Options'; +import { TextAreaItem } from '../TextAreaItem'; + +import Point from './../../icons/point.svg'; +import Option from './options.svg'; +import { + ChildrenWrapper, + ItemContentWrapper, + OptionsBtnWrapper, + StyledArrowIcon, + StyledButtonWithIcon, + StyledScTagLink, +} from './styled'; + +interface INavigationListProps { + data: ITransformedDecomposition[]; + children?: ReactNode; + deleteable: boolean; + editable: boolean; +} + +export const NavigationListInner = ({ + data, + children, + deleteable, + editable, +}: PropsWithChildren) => { + return ( +
    + {data.map((item) => { + return ( + + ); + })} + {children} +
+ ); +}; + +interface INavigationItemProps { + menuItem: ITransformedDecomposition; + editable: boolean; + deleteable: boolean; +} + +const NavigationItem = ({ menuItem, editable, deleteable }: INavigationItemProps) => { + const [isOptionsOpen, setIsOptionsOpen] = useState(false); + const [isAddInputShow, setIsAddInputShow] = useState(false); + const [isEditInputShow, setIsEditInputShow] = useState(false); + const [addInputValue, setAddInputValue] = useState(''); + + const optionsWrapperRef = useRef(null); + const wrapperAddInputRef = useRef(null); + + const { onToggle, onAdd, onEdit, onDelete } = useDecompositionContext(); + + useEffect(() => { + if (isAddInputShow) { + closeOptions(); + } + }, [isAddInputShow]); + + const onOptionsOpen = () => { + setIsOptionsOpen(!isOptionsOpen); + }; + + const onAddClick = () => { + onAdd(menuItem.id, '', 1); + setIsAddInputShow(true); + }; + + const onEditClick = () => { + setIsEditInputShow(true); + }; + + const closeOptions = () => { + setIsOptionsOpen(false); + }; + + const saveAddItemValue = () => { + if (addInputValue.trim()) onAdd(menuItem.id, addInputValue, Math.random()); + + setIsAddInputShow(false); + closeOptions(); + setAddInputValue(''); + onDelete(1); + }; + + const onChangeAddInput = (e: ChangeEvent) => { + setAddInputValue(e.target.value); + }; + + const onTextAreaAddKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter') { + saveAddItemValue(); + } + + if (e.key === 'Escape') { + setIsAddInputShow(false); + closeOptions(); + setAddInputValue(''); + } + }; + + const onCloseEditTextarea = () => { + setIsEditInputShow(false); + closeOptions(); + }; + + const onUpdateItemValue = (value: string) => { + onEdit(menuItem.id, value); + }; + + useClickOutside(optionsWrapperRef, closeOptions); + useClickOutside(wrapperAddInputRef, saveAddItemValue); + + const renderItemText = (text: string) => ( + <> + {!isEditInputShow && ( + + {text} + + )} + {isEditInputShow && ( + + )} + + ); + + return ( + <> + {menuItem.title && ( +
  • + + onToggle(menuItem.id)} + disabled={!menuItem.children.length} + > + {menuItem.children.length ? ( + + ) : ( + + )} + + + + + + {editable && !isEditInputShow && ( + + + + {isOptionsOpen && ( + { + onDelete(menuItem.id); + closeOptions(); + }} + deleteable={deleteable} + /> + )} + + )} + + {menuItem.expanded && !!menuItem.children.length && ( + + + {isAddInputShow && ( + + )} + + + )} +
  • + )} + + ); +}; + +export const NavigationList = memo(NavigationListInner); diff --git a/src/components/DecompositionPanel/components/NavigationList/index.tsx b/src/components/DecompositionPanel/components/NavigationList/index.tsx new file mode 100644 index 0000000..ad0a38b --- /dev/null +++ b/src/components/DecompositionPanel/components/NavigationList/index.tsx @@ -0,0 +1 @@ +export * from './NavigationList'; diff --git a/src/components/DecompositionPanel/components/NavigationList/options.svg b/src/components/DecompositionPanel/components/NavigationList/options.svg new file mode 100644 index 0000000..60fb68a --- /dev/null +++ b/src/components/DecompositionPanel/components/NavigationList/options.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/DecompositionPanel/components/NavigationList/styled.ts b/src/components/DecompositionPanel/components/NavigationList/styled.ts new file mode 100644 index 0000000..841d73a --- /dev/null +++ b/src/components/DecompositionPanel/components/NavigationList/styled.ts @@ -0,0 +1,103 @@ +import { ButtonWithIcon } from 'ostis-ui-lib'; +import { ScTagLink } from 'ostis-ui-lib'; +import styled, { css, keyframes } from 'styled-components'; + +import ArrowIcon from '../../icons/arrow.svg'; + +export const rotate = keyframes` + from { + opacity: 1; + } + to { + opacity: 0.6; + } +`; + +export const ItemContentWrapper = styled.div<{ isOptionsOpen: boolean; isLoading: boolean }>` + display: grid; + grid-template-columns: 26px 1fr 26px; + align-items: center; + grid-column-gap: 10px; + + padding: 8px 3px 8px 0; + + font-size: 20px; + line-height: 24px; + color: #323232; + + word-break: break-word; + + border-radius: 4px; + + &:hover { + background: #f1f1f1; + + .optionsBtn { + opacity: 1; + } + } + + ${(props) => + props.isOptionsOpen && + css` + background: #f1f1f1; + opacity: 1; + `} + + &isLoading { + animation-name: ${rotate}; + } +`; + +export const StyledButtonWithIcon = styled(ButtonWithIcon)<{ options?: boolean; marker?: boolean }>` + width: 24px; + height: 24px; + + ${(props) => + props.marker && + css` + &:disabled { + cursor: unset; + } + `} + + ${(props) => + props.options && + css` + border-radius: 41px; + + opacity: 0; + + &:hover { + background: #dedede; + } + `} +`; + +export const StyledArrowIcon = styled(ArrowIcon)<{ expanded: boolean }>` + ${(props) => + props.expanded && + css` + transform: rotate(90deg); + `} +`; + +export const OptionsBtnWrapper = styled.div` + position: relative; +`; + +export const ChildrenWrapper = styled.div` + grid-column: 1/4; + + padding: 12px 0 0 16px; + margin-bottom: 12px; +`; + +export const StyledScTagLink = styled(ScTagLink)` + font-size: 20px; + line-height: 24px; + + &::first-letter { + text-transform: uppercase; + } +`; diff --git a/src/components/DecompositionPanel/components/Options/Options.tsx b/src/components/DecompositionPanel/components/Options/Options.tsx new file mode 100644 index 0000000..4406113 --- /dev/null +++ b/src/components/DecompositionPanel/components/Options/Options.tsx @@ -0,0 +1,31 @@ +import { FC } from 'react'; +import { useTranslate } from 'ostis-ui-lib'; + +import { StyledButtonWithIcon, Wrap } from './styled'; + +interface IProps { + onAddClick: () => void; + onEditClick: () => void; + onDeleteClick: () => void; + deleteable: boolean; +} + +export const Options: FC = ({ onAddClick, onEditClick, onDeleteClick, deleteable }) => { + const translate = useTranslate(); + + return ( + + + {translate({ ru: 'Переименовать', en: 'Rename' })} + + {deleteable && ( + + {translate({ ru: 'Удалить', en: 'Delete' })} + + )} + + {translate({ ru: 'Новый подраздел', en: 'New subsection' })} + + + ); +}; diff --git a/src/components/DecompositionPanel/components/Options/index.tsx b/src/components/DecompositionPanel/components/Options/index.tsx new file mode 100644 index 0000000..6e8a171 --- /dev/null +++ b/src/components/DecompositionPanel/components/Options/index.tsx @@ -0,0 +1 @@ +export * from './Options'; diff --git a/src/components/DecompositionPanel/components/Options/styled.ts b/src/components/DecompositionPanel/components/Options/styled.ts new file mode 100644 index 0000000..a0fa88c --- /dev/null +++ b/src/components/DecompositionPanel/components/Options/styled.ts @@ -0,0 +1,40 @@ +import { ButtonWithIcon } from 'ostis-ui-lib'; +import styled from 'styled-components'; + +export const Wrap = styled.div` + position: absolute; + top: 100%; + right: 0; + + min-width: 185px; + + background: #ffffff; + + border: 1px solid rgba(0, 0, 0, 0.12); + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); + border-radius: 10px; + + z-index: 2; +`; + +export const StyledButtonWithIcon = styled(ButtonWithIcon)` + width: 100%; + + padding: 8px 16px; + + border-bottom: 1px solid rgba(0, 0, 0, 0.12); + + font-size: 18px; + line-height: 20px; + + text-align: left; + white-space: nowrap; + + &:hover { + background: #ececec; + } + + &:last-child { + border-bottom: none; + } +`; diff --git a/src/components/DecompositionPanel/components/Skeleton/Skeleton.tsx b/src/components/DecompositionPanel/components/Skeleton/Skeleton.tsx new file mode 100644 index 0000000..8306fc1 --- /dev/null +++ b/src/components/DecompositionPanel/components/Skeleton/Skeleton.tsx @@ -0,0 +1,28 @@ +import { PseudoText } from 'ostis-ui-lib'; + +import { BallWrapper, Root, Wrap } from './styled'; + +export const Skeleton = () => { + return ( + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/src/components/DecompositionPanel/components/Skeleton/index.tsx b/src/components/DecompositionPanel/components/Skeleton/index.tsx new file mode 100644 index 0000000..66bc08d --- /dev/null +++ b/src/components/DecompositionPanel/components/Skeleton/index.tsx @@ -0,0 +1 @@ +export * from './Skeleton'; diff --git a/src/components/DecompositionPanel/components/Skeleton/styled.ts b/src/components/DecompositionPanel/components/Skeleton/styled.ts new file mode 100644 index 0000000..f31d9b5 --- /dev/null +++ b/src/components/DecompositionPanel/components/Skeleton/styled.ts @@ -0,0 +1,21 @@ +import styled from 'styled-components'; + +export const Root = styled.div` + display: flex; + flex-direction: column; + row-gap: 16px; + + padding-top: 8px; +`; + +export const Wrap = styled.div` + display: grid; + grid-template-columns: 40px 1fr; + align-items: center; + grid-column-gap: 10px; +`; + +export const BallWrapper = styled.div` + display: flex; + justify-content: flex-end; +`; diff --git a/src/components/DecompositionPanel/components/TextAreaItem/TextAreaItem.tsx b/src/components/DecompositionPanel/components/TextAreaItem/TextAreaItem.tsx new file mode 100644 index 0000000..ce12a4d --- /dev/null +++ b/src/components/DecompositionPanel/components/TextAreaItem/TextAreaItem.tsx @@ -0,0 +1,20 @@ +import { ChangeEvent, FC, KeyboardEvent, RefObject } from 'react'; + +import PointIcon from './../../icons/point.svg'; +import { StyledTextarea, Wrap } from './styled'; + +interface IProps { + value: string; + wrapperTextareaRef: RefObject; + onChange?: (e: ChangeEvent) => void; + onKeyDown?: (e: KeyboardEvent) => void; +} + +export const TextAreaItem: FC = ({ value, wrapperTextareaRef, onChange, onKeyDown }) => { + return ( + + + + + ); +}; diff --git a/src/components/DecompositionPanel/components/TextAreaItem/index.tsx b/src/components/DecompositionPanel/components/TextAreaItem/index.tsx new file mode 100644 index 0000000..4395f9f --- /dev/null +++ b/src/components/DecompositionPanel/components/TextAreaItem/index.tsx @@ -0,0 +1 @@ +export * from './TextAreaItem'; diff --git a/src/components/DecompositionPanel/components/TextAreaItem/styled.ts b/src/components/DecompositionPanel/components/TextAreaItem/styled.ts new file mode 100644 index 0000000..4f8445c --- /dev/null +++ b/src/components/DecompositionPanel/components/TextAreaItem/styled.ts @@ -0,0 +1,21 @@ +import styled from 'styled-components'; + +import { Textarea } from 'ostis-ui-lib'; + +export const Wrap = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + column-gap: 8px; + + width: 100%; + min-height: 40px; + + padding: 8px 0 8px 6px; +`; + +export const StyledTextarea = styled(Textarea)` + height: 28px; + + overflow: hidden; +`; diff --git a/src/components/DecompositionPanel/icons/arrow.svg b/src/components/DecompositionPanel/icons/arrow.svg new file mode 100644 index 0000000..d4311a7 --- /dev/null +++ b/src/components/DecompositionPanel/icons/arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/DecompositionPanel/icons/point.svg b/src/components/DecompositionPanel/icons/point.svg new file mode 100644 index 0000000..293811b --- /dev/null +++ b/src/components/DecompositionPanel/icons/point.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/DecompositionPanel/index.tsx b/src/components/DecompositionPanel/index.tsx new file mode 100644 index 0000000..a84416d --- /dev/null +++ b/src/components/DecompositionPanel/index.tsx @@ -0,0 +1 @@ +export * from './DecompositionPanel'; diff --git a/src/components/DecompositionPanel/styled.ts b/src/components/DecompositionPanel/styled.ts new file mode 100644 index 0000000..6c5cf77 --- /dev/null +++ b/src/components/DecompositionPanel/styled.ts @@ -0,0 +1,5 @@ +import styled from 'styled-components'; + +export const Nav = styled.nav` + margin-right: 0; +`; diff --git a/src/components/DecompositionPanel/types.ts b/src/components/DecompositionPanel/types.ts new file mode 100644 index 0000000..848d752 --- /dev/null +++ b/src/components/DecompositionPanel/types.ts @@ -0,0 +1,51 @@ +export interface ITransformedDecomposition { + id: number; + title: string; + children: ITransformedDecomposition[]; + expanded: boolean; + isLoading: boolean; +} + +export type Decomposition = Record< + number, + { + idtf: string; + decomposition: Decomposition; + position: number; + } +>; + +export interface IDecompositionItem { + sectionName: string; +} + +export type TAddDecompositionItemCallBack = ( + parentID: string, + data: IDecompositionItem, +) => Promise; + +export type TGetDecompositionCallback = () => Promise; + +export type TEditDecompositionItemCallback = (id: number, value: string) => Promise; + +export type TDeleteDecompositionItemCallback = ( + parentID: string, + id: string, +) => Promise; + +export interface IDecompositionContext { + isMenuListLoading: boolean; + setIsMenuListLoading: React.Dispatch>; + menuList: ITransformedDecomposition | null; + setMenuList: React.Dispatch>; + isAddInputShow: boolean; + setIsAddInputShow: React.Dispatch>; + addInputValue: string; + setAddInputValue: React.Dispatch>; + onToggle: (id: number) => void; + onToggleShowItem: (id: number) => void; + onAdd: (id: number, value: string, elemID: number) => Promise; + onEdit: (id: number, value: string) => Promise; + onDelete: (id: number) => Promise; + onAddClick: () => void; +} diff --git a/src/components/DecompositionPanel/utils/dataTransform.ts b/src/components/DecompositionPanel/utils/dataTransform.ts new file mode 100644 index 0000000..4fe9686 --- /dev/null +++ b/src/components/DecompositionPanel/utils/dataTransform.ts @@ -0,0 +1,15 @@ +import { Decomposition, ITransformedDecomposition } from '@model/model'; + +export const dataTransform = (data: Decomposition): ITransformedDecomposition[] => { + return Object.entries(data) + .sort((left, right) => left[1].position - right[1].position) + .map(([key, value]) => { + return { + id: Number(key), + title: value.idtf, + children: value.decomposition ? dataTransform(value.decomposition) : [], + expanded: false, + isLoading: false, + }; + }); +}; diff --git a/src/components/DecompositionPanel/utils/getElemPath.ts b/src/components/DecompositionPanel/utils/getElemPath.ts new file mode 100644 index 0000000..7a84dd9 --- /dev/null +++ b/src/components/DecompositionPanel/utils/getElemPath.ts @@ -0,0 +1,54 @@ +import { ITransformedDecomposition } from '../types'; + +const getElemPath = (tree: ITransformedDecomposition, id: number): number[] => { + if (tree.id === id) return [tree.id]; + + for (const elem of tree.children) { + const path = getElemPath(elem, id); + if (path.length) return [tree.id, ...path]; + } + return []; +}; + +const updateByPath = ( + tree: ITransformedDecomposition, + paths: number[], + id: number, + cb: (elem: ITransformedDecomposition) => ITransformedDecomposition, +): ITransformedDecomposition => { + if (!paths.includes(tree.id)) return tree; + + if (tree.id === id) return cb(tree); + + const innerUpdated = tree.children.some((child) => paths.includes(child.id)); + return { + ...tree, + children: innerUpdated + ? tree.children.map((child) => updateByPath(child, paths, id, cb)) + : tree.children, + }; +}; + +export const findParent = ( + tree: ITransformedDecomposition, + id: number, +): ITransformedDecomposition | null => { + if (tree.children.find((elem) => elem.id === id)) return tree; + + for (const child of tree.children) { + const elem = findParent(child, id); + + if (elem) return elem; + } + + return null; +}; + +export const updateElem = ( + tree: ITransformedDecomposition, + id: number, + cb: (elem: ITransformedDecomposition) => ITransformedDecomposition, +) => { + const paths = getElemPath(tree, id); + return updateByPath(tree, paths, id, cb); +}; diff --git a/src/components/DevModeSwitch/DevModeSwitch.module.scss b/src/components/DevModeSwitch/DevModeSwitch.module.scss new file mode 100644 index 0000000..e251e80 --- /dev/null +++ b/src/components/DevModeSwitch/DevModeSwitch.module.scss @@ -0,0 +1,39 @@ +@import '~@assets/styles/variables/colors.scss'; + +.switch { + position: relative; + display: inline-block; + width: 69px; + height: 36px; +} + +.switch input[type='checkbox'] { + opacity: 0; + width: 0; + height: 0; +} + +.sliderRound { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: $popup-border; + -webkit-transition: 0.4s; + transition: 0.4s; + border-radius: 35px; +} + +.switchIcon { + position: absolute; + left: 3px; + top: 3px; + -webkit-transition: 0.4s; + transition: 0.4s; +} + +input:checked + .sliderRound .switchIcon { + left: 36px; +} diff --git a/src/components/DevModeSwitch/DevModeSwitch.tsx b/src/components/DevModeSwitch/DevModeSwitch.tsx new file mode 100644 index 0000000..eff51c4 --- /dev/null +++ b/src/components/DevModeSwitch/DevModeSwitch.tsx @@ -0,0 +1,36 @@ +import { useState } from 'react'; +import { useDispatch } from 'react-redux'; +import { setDevMode } from '@store/devModeSlice'; +import styles from './DevModeSwitch.module.scss'; +import DevModeON from '@assets/images/DevModeON.svg'; +import DevModeOFF from '@assets/images/DevModeOFF.svg'; + +export const DevModeSwitch = () => { + const dispatch = useDispatch(); + + const [checked, setChecked] = useState(() => { + const storedValue = localStorage.getItem('devMode'); + return storedValue ? JSON.parse(storedValue) : false; + }); + + const handleChange = () => { + setChecked(!checked); + localStorage.setItem('devMode', JSON.stringify(!checked)); + dispatch(setDevMode(!checked)); + }; + + return ( +
    + +
    + ); +}; diff --git a/src/components/DevModeSwitch/index.tsx b/src/components/DevModeSwitch/index.tsx new file mode 100644 index 0000000..64e35ff --- /dev/null +++ b/src/components/DevModeSwitch/index.tsx @@ -0,0 +1 @@ +export * from './DevModeSwitch'; diff --git a/src/components/HistoryPanel/HistoryPanel.tsx b/src/components/HistoryPanel/HistoryPanel.tsx index 4229b80..bddacad 100644 --- a/src/components/HistoryPanel/HistoryPanel.tsx +++ b/src/components/HistoryPanel/HistoryPanel.tsx @@ -9,6 +9,8 @@ import styles from './HistoryPanel.module.scss'; import { Skeleton } from './Skeleton'; +import { Tooltip } from '@components/ToolTip/ToolTip'; + interface IProps { isLoading: boolean; requests: IRequest[]; @@ -37,7 +39,9 @@ export const HistoryPanel = (props: IProps) => { addr={question} onClick={onBtnClick(String(question))} > - + + + ))}
    diff --git a/src/components/Language/Language.tsx b/src/components/Language/Language.tsx index 8ecad36..1fd7f1c 100644 --- a/src/components/Language/Language.tsx +++ b/src/components/Language/Language.tsx @@ -1,9 +1,18 @@ import classNames from 'classnames'; import { TLanguage, useLanguageContext } from 'ostis-ui-lib'; +import { Tooltip } from '@components/ToolTip/ToolTip'; import styles from './language.module.scss'; +import { FC } from 'react'; -export const Language = () => { +type HEXColor = `#${string}`; + +interface ILanguageProps { + primaryLanguageColor?: HEXColor; + secondaryLanguageColor?: HEXColor; +} + +export const Language: FC = ({ primaryLanguageColor, secondaryLanguageColor }) => { const { lang, setLang } = useLanguageContext(); const setLanguage = (lang: TLanguage) => () => { @@ -11,26 +20,35 @@ export const Language = () => { setLang(lang); }; + const primaryLanguageStyle = primaryLanguageColor ? { color: primaryLanguageColor } : {}; + const secondaryLanguageStyle = secondaryLanguageColor ? { color: secondaryLanguageColor } : {}; + return (
    - - En - - - - Ru - + + + En + + + + + + Ru + +
    ); diff --git a/src/components/Layout/AuthLayout/AuthLayout.module.scss b/src/components/Layout/AuthLayout/AuthLayout.module.scss new file mode 100644 index 0000000..1cf925b --- /dev/null +++ b/src/components/Layout/AuthLayout/AuthLayout.module.scss @@ -0,0 +1,84 @@ +@import '~@assets/styles/variables/colors.scss'; + +.root { + background: $beige; + display: grid; + grid-template-columns: minmax(0, 463px) 1fr; + grid-template-rows: 80px 1fr; + grid-template-areas: + 'logo language' + 'main main'; + min-height: 100vh; + min-width: 100vw; + + .header { + display: flex; + z-index: 99; + align-items: center; + justify-content: flex-end; + grid-area: language; + width: 100%; + padding-right: 24px; + } + + .logoWrapper { + height: 100px; + width: 100%; + grid-area: logo; + display: flex; + justify-content: flex-start; + align-items: center; + background: $beige; + padding-left: 24px; + } + + .main { + display: flex; + justify-content: start; + height: 100%; + width: 35%; + padding-top: 36px; + padding-left: 24px; + grid-area: main; + } + + .authPageImage { + height: 100vh; + position: absolute; + top: 0px; + right: 0px; + z-index: 1; + + @media (max-width: 1200px) { + display: none; + padding: 0; + } + } + + .innerAuthPageImage { + height: 100%; + } + + @media (max-width: 1200px) { + display: flex; + flex-direction: column; + + .header { + position: absolute; + top: 20px; + right: 0px; + z-index: 1; + } + + .main { + padding: 0; + width: 100%; + } + } +} + +.languageWrapper { + width: 100%; + display: flex; + justify-content: flex-end; +} diff --git a/src/components/Layout/AuthLayout/AuthLayout.tsx b/src/components/Layout/AuthLayout/AuthLayout.tsx new file mode 100644 index 0000000..40e6ac0 --- /dev/null +++ b/src/components/Layout/AuthLayout/AuthLayout.tsx @@ -0,0 +1,44 @@ +import { FC, ReactNode } from 'react'; + +import { useDispatch } from 'react-redux'; +import { Link } from 'react-router-dom'; + +import Logo from '@assets/images/Logo.svg'; + +import { Language } from '@components/Language'; +import { routes } from '@constants'; +import { setActiveLink } from '@store/activeLinkSlice'; + +import AuthPageImage from '@assets/images/authPage.png'; + +import styles from './AuthLayout.module.scss'; + +export interface IProps { + children?: ReactNode; +} +export const AuthLayout: FC = ({ children }) => { + const dispatch = useDispatch(); + + const handleLogoOnClick = () => { + dispatch(setActiveLink({ newActiveLink: routes.MAIN })); + }; + + return ( +
    +
    + + + +
    +
    +
    + +
    +
    +
    {children}
    +
    + +
    +
    + ); +}; diff --git a/src/components/Layout/AuthLayout/index.tsx b/src/components/Layout/AuthLayout/index.tsx new file mode 100644 index 0000000..654e0e0 --- /dev/null +++ b/src/components/Layout/AuthLayout/index.tsx @@ -0,0 +1 @@ +export * from './AuthLayout'; diff --git a/src/components/Layout/Layout.module.scss b/src/components/Layout/Layout.module.scss index 08d6904..3adda80 100644 --- a/src/components/Layout/Layout.module.scss +++ b/src/components/Layout/Layout.module.scss @@ -8,7 +8,7 @@ grid-template-rows: 80px 1fr; grid-template-areas: 'logo header' - 'sidebar scn'; + 'sidebar scn'; min-height: 100%; @@ -21,7 +21,7 @@ justify-content: end; grid-area: header; width: 100%; - padding: 0px 24px 0 0; + padding: 0px 24px 0 0; } .sideBar { @@ -50,8 +50,7 @@ .languageWrapper { width: 100%; - display: flex; - justify-content: flex-end; + display: inline-block; } .sideBarContent { @@ -70,3 +69,98 @@ grid-template-columns: minmax(0px, 25%) 1fr; } } + +.authHeaderButtonWrapper { + display: flex; + justify-content: space-between; + align-items: center; + width: 180px; + height: 42px; + gap: 32px; + margin-right: 50px; +} + +.unauthHeaderButtonWrapper { + display: flex; + justify-content: space-between; + align-items: center; + width: 380px; + height: 42px; + gap: 32px; +} + +.authWrapper { + padding: 10px; +} + +.profileWrapper { + width: 108px; + height: 42px; + display: flex; + gap: 8px; +} + +.profileWrapperWithLogout { + background: #f7f7f7; +} + +.profileUsername { + text-align: center; + line-height: 36px; + padding-left: 5px; + font-family: Roboto; + font-size: 20px; + font-weight: 400; + text-align: left; +} + +.logInButton { + width: 108px; + height: 42px; + color: $navy-blue; + cursor: pointer; + background: none; + border: none; + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + font-size: 22px; + line-height: 26px; +} + +.logInButton:hover { + background: $white; + border: 2px solid #dbdbdb; + border-radius: 10px; +} + +.logoutWrapper { + display: flex; + position: absolute; + width: 128px; + top: 60px; + right: 25px; + z-index: 9999; + flex-direction: column; +} + +.logoutButton { + display: block; + margin-top: 20px; + text-align: center; + background: #f7f7f7; + cursor: pointer; + border: none; + width: 127px; + height: 54px; + font-family: Roboto; + font-size: 22px; + font-weight: 400; + color: #737373; + line-height: 25.78px; + text-align: center; + + &:hover { + background: #dbdbdb; + } +} diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index a38b529..ce6db8c 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -1,15 +1,24 @@ -import { FC, ReactNode } from 'react'; +import { FC, ReactNode, useState } from 'react'; import { ScgPage } from '@components/ScgPage'; import { SidePanel } from '@components/SidePanel'; import { SidePanelWrapper } from '@components/SidePanelWrapper'; +import cn from 'classnames'; + import styles from './Layout.module.scss'; import { Language } from '@components/Language'; -import { Link } from 'react-router-dom'; +import { DevModeSwitch } from '@components/DevModeSwitch'; +import { Link, useNavigate } from 'react-router-dom'; import Logo from '@assets/images/Logo.svg'; import { routes } from '@constants'; import { setActiveLink } from '@store/activeLinkSlice'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; +import { useTranslate } from 'ostis-ui-lib'; +import { Tooltip } from '@components/ToolTip/ToolTip'; +import { selectAuth, setUsername } from '@store/authSlice'; + +import UserIcon from '@assets/images/UserIcon.svg'; +import GoBackIcon from '@assets/images/goBackDark.svg'; export interface IProps { children?: ReactNode; @@ -17,21 +26,86 @@ export interface IProps { export const Layout: FC = ({ children }) => { const dispatch = useDispatch(); + const translate = useTranslate(); + const navigate = useNavigate(); + + const [logout, setLogout] = useState(); + + const username = useSelector(selectAuth); const handleLogoOnClick = () => { dispatch(setActiveLink({ newActiveLink: routes.MAIN })); }; + const handleLogInButtonClick = (evt: React.MouseEvent) => { + evt.preventDefault(); + return navigate(routes.AUTH); + }; + + const handleLogOutButtonClick = (evt: React.MouseEvent) => { + evt.preventDefault(); + dispatch(setUsername({ username: '' })); + }; + return (
    - + + +
    -
    - +
    +
    + + + +
    + {username == '' ? ( +
    + +
    + ) : ( + <> + )} +
    + {username != '' ? ( +
    setLogout(!logout)}> + +
    {username}
    + {logout ? ( +
    +
    + + +
    +
    + ) : ( + <> + )} +
    + ) : ( + + + + )} +
    diff --git a/src/components/Router/Router.tsx b/src/components/Router/Router.tsx index 2545aa8..09e9466 100644 --- a/src/components/Router/Router.tsx +++ b/src/components/Router/Router.tsx @@ -5,6 +5,8 @@ import { routes, DEFAULT_COMMAND_PATH } from '@constants'; import { Command } from '@pages/Command'; import { Main } from '@pages/Main'; import { Question } from '@pages/Question'; +import { Auth } from '@pages/Auth'; +import { AuthLayout } from '@components/Layout/AuthLayout'; import { Library } from '@pages/Library' export const Router = () => { @@ -24,6 +26,14 @@ export const Router = () => { } /> } /> + + + + } + /> ); diff --git a/src/components/Scg/styled.ts b/src/components/Scg/styled.ts index a07ee5b..93152d3 100644 --- a/src/components/Scg/styled.ts +++ b/src/components/Scg/styled.ts @@ -1,5 +1,5 @@ import { Spinner } from 'ostis-ui-lib'; -import styled from 'styled-components'; +import { styled } from 'styled-components'; export const Wrap = styled.div<{ show?: boolean }>` position: absolute; @@ -29,15 +29,15 @@ export const Frame = styled.iframe` border: 0; `; -export const Popup = styled.div<{ isClear?: boolean }>` - width: ${(props) => (props.isClear ? '383px' : '344px')}; - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - font-size: 18px; - line-height: 21px; - color: #323232; - b { - font-weight: 500; - } +export const Popup = styled.div<{ isClear?: boolean }>` + width: ${(props) => (props.isClear ? '383px' : '344px')}; + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + font-size: 18px; + line-height: 21px; + color: #323232; + b { + font-weight: 500; + } `; diff --git a/src/components/Scn/Scn.module.scss b/src/components/Scn/Scn.module.scss index 0ad0909..535c99e 100644 --- a/src/components/Scn/Scn.module.scss +++ b/src/components/Scn/Scn.module.scss @@ -5,4 +5,4 @@ .container { padding-right: 120px; -} \ No newline at end of file +} diff --git a/src/components/Scn/Scn.tsx b/src/components/Scn/Scn.tsx index ecc3ea4..bab71e2 100644 --- a/src/components/Scn/Scn.tsx +++ b/src/components/Scn/Scn.tsx @@ -1,4 +1,5 @@ -import { IScnNode, Scn as ScnBase, useToast, useTranslate } from 'ostis-ui-lib'; +import { IScnNode, useToast, useTranslate } from 'ostis-ui-lib'; +import { Scn as ScnBase } from '@components/ScnBase'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router'; import { doCommand } from '@api/requests/command'; diff --git a/src/components/ScnBase/Scn.tsx b/src/components/ScnBase/Scn.tsx new file mode 100644 index 0000000..d2cc6fb --- /dev/null +++ b/src/components/ScnBase/Scn.tsx @@ -0,0 +1,57 @@ +import { ReactNode, useEffect, useMemo } from 'react'; +import { useInfiniteScroll } from 'ostis-ui-lib'; + +import { ScnElement } from './components/ScnElement'; +import { ScnSkeleton } from './components/ScnSkeleton'; +import { IScnNode } from './model'; +import { ScnProvider, TOnAskQuestion } from './ScnContext'; +import { Inner, StyledScTag, Target } from './styled'; + +const PAGE_SIZE = 25; + +interface IProps { + tree: IScnNode | null; + scgUrl: string; + isLoading?: boolean; + question: number; + renderRequestPanel?: (addr: number) => ReactNode; + onAskQuestion: TOnAskQuestion; + className?: string; +} + +export const Scn = ({ + isLoading, + tree, + scgUrl, + renderRequestPanel, + onAskQuestion, + question, + className, +}: IProps) => { + const { page, scrollRef, targetRef } = useInfiniteScroll({ + total: tree?.children?.length || 1, + pageSize: PAGE_SIZE, + }); + + useEffect(() => { + scrollRef.current?.scroll(0, 0); + }, []); + + const partialTree = useMemo(() => { + if (!tree) return null; + return { ...tree, children: tree.children?.slice(0, page * PAGE_SIZE) }; + }, [tree, page]); + + return ( + + + + {isLoading && } + {partialTree && !isLoading && } + {partialTree && renderRequestPanel && renderRequestPanel(partialTree.addr)} + + + + + ); +}; diff --git a/src/components/ScnBase/ScnContext.tsx b/src/components/ScnBase/ScnContext.tsx new file mode 100644 index 0000000..fd65074 --- /dev/null +++ b/src/components/ScnBase/ScnContext.tsx @@ -0,0 +1,16 @@ +import { createContext, PropsWithChildren, useContext } from 'react'; + +export type TOnAskQuestion = (addr: number) => number | null | Promise; + +export interface IScnContext { + scgUrl: string; + onAskQuestion: TOnAskQuestion; +} + +const SCnContext = createContext({} as IScnContext); + +export const useScnContext = () => useContext(SCnContext); + +export const ScnProvider = ({ children, ...rest }: PropsWithChildren) => { + return {children}; +}; diff --git a/src/components/ScnBase/ScnStory.tsx b/src/components/ScnBase/ScnStory.tsx new file mode 100644 index 0000000..c361325 --- /dev/null +++ b/src/components/ScnBase/ScnStory.tsx @@ -0,0 +1,10 @@ +import { tree1 } from './mock'; +import { Scn } from './Scn'; + +export const ScnStory = () => { + const onAskQuestion = () => { + return null; + }; + + return ; +}; diff --git a/src/components/ScnBase/components/Nodes/Nodes.tsx b/src/components/ScnBase/components/Nodes/Nodes.tsx new file mode 100644 index 0000000..ee986bd --- /dev/null +++ b/src/components/ScnBase/components/Nodes/Nodes.tsx @@ -0,0 +1,80 @@ +import { FC, PropsWithChildren } from 'react'; +import { IScnNode } from '@components/ScnBase/model'; +import { ScType } from 'ts-sc-client'; + +import { ScLink } from '../ScLink'; +import { ScnEdge } from '../ScnEdge'; +import { ScnLink } from '../ScnLink'; + +import { KeywordLinkWrapper, LeftSide, StyledScnLink } from './styled'; + +interface INodeProps { + tree: IScnNode; +} + +const KeywordLinkNode: FC = ({ tree }) => { + const { addr } = tree; + return ( + <> + + + = + + + + ); +}; + +// export const KeywordNode: FC = ({ children, tree }) => { +export const KeywordNode = ({ children, tree }: PropsWithChildren) => { + const { addr, type } = tree; + const scType = new ScType(type); + + const getComp = () => { + if (scType.isEdge()) return ; + if (scType.isLink()) return ; + return ; + }; + + return ( + <> + {getComp()} + {children} + + ); +}; + +export const LinkNode = ({ + children, + tree: { addr, content, contentType }, +}: PropsWithChildren) => ( + <> + + {children} + +); + +export const EdgeNode = ({ children, tree }: PropsWithChildren) => ( + <> + + {children} + +); + +export const TupleNode = ({ children, tree }: PropsWithChildren) => { + if (!tree.children) return ; + return ( + <> + { + {children} + } + + ); +}; + +export const SimpleNode = ({ tree: { addr }, children }: PropsWithChildren) => ( + <> + + {children} + +); diff --git a/src/components/ScnBase/components/Nodes/index.tsx b/src/components/ScnBase/components/Nodes/index.tsx new file mode 100644 index 0000000..c315d19 --- /dev/null +++ b/src/components/ScnBase/components/Nodes/index.tsx @@ -0,0 +1 @@ +export * from './Nodes'; diff --git a/src/components/ScnBase/components/Nodes/styled.ts b/src/components/ScnBase/components/Nodes/styled.ts new file mode 100644 index 0000000..93c3cd6 --- /dev/null +++ b/src/components/ScnBase/components/Nodes/styled.ts @@ -0,0 +1,21 @@ +import styled from 'styled-components'; + +import { ScnLink } from '../ScnLink'; + +export const StyledScnLink = styled(ScnLink)` + font-weight: 500; + line-height: 26px; + font-size: 22px; +`; + +export const KeywordLinkWrapper = styled.div` + display: flex; +`; + +export const LeftSide = styled.span` + width: 20px; + + color: #2a6496; + + flex-shrink: 0; +`; diff --git a/src/components/ScnBase/components/ScLink/ScLink.tsx b/src/components/ScnBase/components/ScLink/ScLink.tsx new file mode 100644 index 0000000..cc9a287 --- /dev/null +++ b/src/components/ScnBase/components/ScLink/ScLink.tsx @@ -0,0 +1,117 @@ +import { useCallback, useEffect, useState } from 'react'; +import { useClient } from 'ostis-ui-lib'; +import { TLinkFormat } from '@components/ScnBase/model'; +import { useInView } from 'ostis-ui-lib'; +import { ScAddr } from 'ts-sc-client'; + +import { voidElements } from './constants'; +import { StyledScnLink, StyledScTag, StyledScTagLink } from './styled'; +import { useDifferedLinkContent } from './useDifferedLinkContent'; +import { Tooltip } from 'ostis-ui-lib'; + +interface IProps { + addr: number; + contentType?: TLinkFormat | null; + content?: string | null; +} + +interface IHtmlNodeToReactProps { + node: ChildNode; +} + +// const nodeAttributesToObject = (node: HTMLElement) => { +// if (!node.hasAttributes()) return {}; +// return Array.from(node.attributes).reduce((acc, curr) => { +// if(curr.name === "style") { +// console.log(node) +// return acc; +// } +// return { +// ...acc, +// [curr.name]: curr.value, +// }; +// }, {}); +// }; + +const HtmlNodeToReact = ({ node }: IHtmlNodeToReactProps) => { + if (node instanceof Text) return <>{node.textContent}; + if (node.nodeName === 'SC_ELEMENT') { + const systemId = + (node as HTMLElement).attributes.getNamedItem('sys_idtf')?.nodeValue || undefined; + return ; + } + if (!(node instanceof HTMLElement)) return null; + + const isVoidElem = voidElements.includes(node.nodeName.toLowerCase()); + const Tag = node.nodeName.toLowerCase() as keyof JSX.IntrinsicElements; + + if (isVoidElem) return ; + + return ( + + {Array.from(node.childNodes).map((childNode, ind) => ( + + ))} + + ); +}; + +const ScLinkHtml = ({ addr }: IProps) => { + const [contentHtml, setContentHtml] = useState(null); + const [targetRef, isInView] = useInView(); + const client = useClient(); + + const parseHtml = useCallback(async () => { + const [{ data }] = await client.getLinkContents([new ScAddr(addr)]); + + if (!data) return; + const parser = new DOMParser(); + const dom = parser.parseFromString(String(data).trim(), 'text/html'); + const contentHtmlObject = dom.querySelector('body') as HTMLElement; + setContentHtml(contentHtmlObject || null); + }, [addr, client]); + + useEffect(() => { + if (isInView) { + parseHtml(); + } + }, [parseHtml, isInView]); + + return ( + + {contentHtml && + Array.from(contentHtml.childNodes).map((childNode, ind) => ( + + ))} + {!contentHtml && } + + ); +}; + +const ScLinkContent = ({ addr, contentType }: IProps) => { + const { content, targetRef } = useDifferedLinkContent(addr); + + if (contentType === 'format_html') { + return ; + } + + return ( + + + {content && contentType === 'format_png' && ( + + )} + {contentType !== 'format_png' && <>{content}} + {!content && } + + + ); +}; + +export const ScLink = ({ addr, contentType }: IProps) => { + return ( + + + + ); +}; diff --git a/src/components/ScnBase/components/ScLink/constants.ts b/src/components/ScnBase/components/ScLink/constants.ts new file mode 100644 index 0000000..59b2c6e --- /dev/null +++ b/src/components/ScnBase/components/ScLink/constants.ts @@ -0,0 +1,25 @@ +export const voidElements = [ + 'area', + 'base', + 'basefont', + 'bgsound', + 'br', + 'col', + 'command', + 'embed', + 'frame', + 'hr', + 'image', + 'img', + 'input', + 'isindex', + 'keygen', + 'link', + 'menuitem', + 'meta', + 'nextid', + 'param', + 'source', + 'track', + 'wbr', +]; diff --git a/src/components/ScnBase/components/ScLink/index.tsx b/src/components/ScnBase/components/ScLink/index.tsx new file mode 100644 index 0000000..43cc3ad --- /dev/null +++ b/src/components/ScnBase/components/ScLink/index.tsx @@ -0,0 +1 @@ +export * from './ScLink'; diff --git a/src/components/ScnBase/components/ScLink/styled.ts b/src/components/ScnBase/components/ScLink/styled.ts new file mode 100644 index 0000000..61474dd --- /dev/null +++ b/src/components/ScnBase/components/ScLink/styled.ts @@ -0,0 +1,55 @@ +import styled, { css } from 'styled-components'; + +import { ScTag, ScTagLink } from 'ostis-ui-lib'; +import { ScnLink } from '../ScnLink'; + +export const StyledScTag = styled(ScTag)<{ isHTML?: boolean }>` + display: flex; + gap: 2px; + + padding: 8px; + + font-size: 18px; + line-height: 21px; + color: #000000; + + ${(props) => + props.isHTML && + css` + display: block; + + p:first-of-type { + margin-top: 0; + } + `} +`; + +export const StyledScTagLink = styled(ScTagLink)` + display: block; + + text-decoration: none; + + box-shadow: inset 0 0 0 1px #d8d8d8; + + background: linear-gradient(135deg, #d9d9d9 12px, transparent 12px); + + transition: all ease 0.15s; + + width: fit-content; + + word-break: break-word; + + &:hover { + background-color: #ededed; + + opacity: 1; + } + + &:active { + box-shadow: inset 0 0 0 3px #d8d8d8; + } +`; + +export const StyledScnLink = styled(ScnLink)` + display: inline; +`; diff --git a/src/components/ScnBase/components/ScLink/useDifferedLinkContent.ts b/src/components/ScnBase/components/ScLink/useDifferedLinkContent.ts new file mode 100644 index 0000000..154c70e --- /dev/null +++ b/src/components/ScnBase/components/ScLink/useDifferedLinkContent.ts @@ -0,0 +1,24 @@ +import { useCallback, useEffect, useState } from 'react'; +import { useClient } from 'ostis-ui-lib'; +import { useInView } from 'ostis-ui-lib'; +import { ScAddr } from 'ts-sc-client'; + +export const useDifferedLinkContent = (addr: number) => { + const [content, setContent] = useState(null); + const [targetRef, isInView] = useInView(); + const client = useClient(); + + const getBase64 = useCallback(async () => { + const [{ data }] = await client.getLinkContents([new ScAddr(addr)]); + if (!data) return; + setContent(String(data).trim()); + }, [addr, client]); + + useEffect(() => { + if (isInView) { + getBase64(); + } + }, [getBase64, isInView]); + + return { content, targetRef }; +}; diff --git a/src/components/ScnBase/components/ScStruct/styled.ts b/src/components/ScnBase/components/ScStruct/styled.ts new file mode 100644 index 0000000..cdab53a --- /dev/null +++ b/src/components/ScnBase/components/ScStruct/styled.ts @@ -0,0 +1,47 @@ +import { Scg } from 'ostis-ui-lib'; +import { Spinner } from 'ostis-ui-lib'; +import { SwitchScgScn } from '@components/SwitchScgScn'; +import styled, { css } from 'styled-components'; + +export const Struct = styled.div<{ isScg?: boolean }>` + border: solid 1px #96a399; + + background-color: #fdfdfd; + + padding: 8px; + + border-radius: 8px; + + width: 100%; + + position: relative; + + overflow: hidden; + + ${({ isScg }) => + isScg && + css` + padding: 0; + `} +`; + +export const StyledSwitchScgScn = styled(SwitchScgScn)` + top: 8px !important; +`; + +export const StyledScg = styled(Scg)` + position: relative; + + min-height: 1024px; + + iframe { + margin: 0 !important; + } +`; + +export const StyledSpinner = styled(Spinner)` + position: absolute; + left: 50%; + top: 20px; + transform: translateX(-50%); +`; diff --git a/src/components/ScnBase/components/ScnEdge/ScnEdge.tsx b/src/components/ScnBase/components/ScnEdge/ScnEdge.tsx new file mode 100644 index 0000000..1ddb232 --- /dev/null +++ b/src/components/ScnBase/components/ScnEdge/ScnEdge.tsx @@ -0,0 +1,30 @@ +import { IScnNode } from 'ostis-ui-lib'; +import { getRandomInt } from 'ostis-ui-lib'; + +import { arcMap } from '../../constants'; +import { ScnLink } from '../ScnLink'; + +import { EdgeInner, EdgeWrapper, StyledScTagLink } from './styled'; + +interface IProps { + className?: string; + node: IScnNode; +} + +export const ScnEdge = ({ node: { addr, type, sourceNode, targetNode } }: IProps) => { + if (!sourceNode || !targetNode) return null; + + return ( + + ( + + + + {arcMap[type].right} + + + + ) + + ); +}; diff --git a/src/components/ScnBase/components/ScnEdge/index.tsx b/src/components/ScnBase/components/ScnEdge/index.tsx new file mode 100644 index 0000000..21656f1 --- /dev/null +++ b/src/components/ScnBase/components/ScnEdge/index.tsx @@ -0,0 +1 @@ +export * from './ScnEdge'; diff --git a/src/components/ScnBase/components/ScnEdge/styled.ts b/src/components/ScnBase/components/ScnEdge/styled.ts new file mode 100644 index 0000000..d189d40 --- /dev/null +++ b/src/components/ScnBase/components/ScnEdge/styled.ts @@ -0,0 +1,16 @@ +import { ScTagLink } from 'ostis-ui-lib'; +import styled from 'styled-components'; + +export const EdgeWrapper = styled.div` + display: flex; + align-items: center; +`; + +export const EdgeInner = styled.div` + display: flex; + align-items: center; +`; + +export const StyledScTagLink = styled(ScTagLink)` + margin: 0 4px; +`; diff --git a/src/components/ScnBase/components/ScnElement/ScnElement.tsx b/src/components/ScnBase/components/ScnElement/ScnElement.tsx new file mode 100644 index 0000000..e7434c6 --- /dev/null +++ b/src/components/ScnBase/components/ScnElement/ScnElement.tsx @@ -0,0 +1,186 @@ +import { Fragment, memo, PropsWithChildren, useCallback, useEffect, useState } from 'react'; +import { useClient } from 'ostis-ui-lib'; +import { useLanguage } from 'ostis-ui-lib'; +import { IScnNode } from '@components/ScnBase/model'; +import { useScnContext } from '@components/ScnBase/ScnContext'; +import { useScUtils } from 'ostis-ui-lib'; +import { TScLanguageTab } from 'ostis-ui-lib'; +import { langToKeynode } from 'ostis-ui-lib'; +import { snakeToCamelCase } from 'ostis-ui-lib'; +import { ScAddr, ScTemplate, ScType } from 'ts-sc-client'; + +import { arcMap } from '../../constants'; +import { EdgeNode, KeywordNode, LinkNode, SimpleNode, TupleNode } from '../Nodes'; +import { ScnLink } from '../ScnLink'; +import { Struct, StyledScg, StyledSpinner, StyledSwitchScgScn } from '../ScStruct/styled'; + +import { + Arc, + Child, + LinkedNodes, + Marker, + Modifier, + RightSide, + StyledLinkedNode, + Wrapper, +} from './styled'; +import { getRandomInt } from 'ostis-ui-lib'; + +const SPINER_COLOR = '#5896C0'; + +interface IProps { + tree: IScnNode; + isLoading?: boolean; + isRoot?: boolean; +} + +interface IModifierArcProps { + type: number; +} + +const ModifierArc = ({ type }: IModifierArcProps) => { + const scType = new ScType(type); + if (scType.isConst()) return <>:; + return <>::; +}; + +const ScStruct = ({ tree }: IProps) => { + const [isLoading, setIsLoading] = useState(false); + const [question, setQuestion] = useState(null); + const [tab, setTab] = useState('scn'); + + const { onAskQuestion, scgUrl } = useScnContext(); + + const getQuestion = useCallback(async () => { + setIsLoading(true); + const question = await onAskQuestion(tree.addr); + setIsLoading(false); + setQuestion(question); + }, [onAskQuestion, tree.addr]); + + useEffect(() => { + getQuestion(); + }, [getQuestion]); + + const showScg = tab === 'scg'; + const renderScg = showScg && !!question && !isLoading; + return ( + + + {!showScg && } + + {showScg && isLoading && } + + ); +}; + +interface ILinkedNodeProps { + node: IScnNode; + showMarker?: boolean; +} + +const LinkedNode = ({ node, showMarker }: PropsWithChildren) => { + const [show, setShow] = useState(true); + + const lang = useLanguage(); + const client = useClient(); + const { findKeynodes } = useScUtils(); + + const scType = new ScType(node.type); + + const isLink = scType.isLink(); + + useEffect(() => { + if (!isLink) return setShow(true); + + (async () => { + const { languages, ...rest } = await findKeynodes('languages', langToKeynode[lang]); + + const activeLangKeynode = rest[snakeToCamelCase(langToKeynode[lang])]; + + const template = new ScTemplate(); + + const langAlias = '_lang'; + + template.triple(languages, ScType.EdgeAccessVarPosPerm, [ScType.NodeVarClass, langAlias]); + template.triple(langAlias, ScType.EdgeAccessVarPosPerm, new ScAddr(node.addr)); + const result = await client.templateSearch(template); + if (!result.length) return setShow(true); + const foundLang = result[0].get(langAlias); + setShow(foundLang.value === activeLangKeynode.value); + })(); + }, [client, findKeynodes, isLink, lang, node.addr]); + + if (!show) return null; + + return ( + + {showMarker && } + + + ); +}; + +const ScnElementWrapper = ({ tree, isRoot = false }: IProps) => { + const { children, type, struct } = tree; + const scType = new ScType(type); + + const getNode = () => { + if (isRoot) return KeywordNode; + if (scType.isLink()) return LinkNode; + if (scType.isEdge()) return EdgeNode; + if (scType.isTuple()) return TupleNode; + return SimpleNode; + }; + const Node = getNode(); + + const isTuple = scType.isTuple(); + + return ( + + + {children?.map(({ arcs: [arc], modifiers, linkedNodes }) => ( + + {!isTuple && {arcMap[arc.type]?.[arc.direction]}} + {isTuple && } + + {modifiers && ( + + {modifiers.map((modifier) => ( + + + + + ))} + + )} + + {linkedNodes.map((linkedNode, linkedNodeInd) => ( + 1} + node={linkedNode} + /> + ))} + + + + ))} + {struct && ( + + = + + + + + )} + + + ); +}; + +export const ScnElement = memo(ScnElementWrapper); diff --git a/src/components/ScnBase/components/ScnElement/index.tsx b/src/components/ScnBase/components/ScnElement/index.tsx new file mode 100644 index 0000000..f5cc2c3 --- /dev/null +++ b/src/components/ScnBase/components/ScnElement/index.tsx @@ -0,0 +1 @@ +export * from './ScnElement'; diff --git a/src/components/ScnBase/components/ScnElement/styled.ts b/src/components/ScnBase/components/ScnElement/styled.ts new file mode 100644 index 0000000..93a6d50 --- /dev/null +++ b/src/components/ScnBase/components/ScnElement/styled.ts @@ -0,0 +1,63 @@ +import styled from 'styled-components'; + +export const StyledLinkedNode = styled.div` + display: flex; +`; + +export const Marker = styled.div` + flex-shrink: 0; + + width: 8px; + height: 8px; + + border-radius: 50%; + + background-color: #2a6496; + + margin-right: 15px; + margin-top: 6px; +`; + +export const Wrapper = styled.div` + font-family: 'Roboto'; + + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 10px; + flex-grow: 1; +`; + +export const Child = styled.div` + display: flex; + + width: 100%; +`; + +export const Arc = styled.div` + width: 20px; + + color: #2a6496; + + flex-shrink: 0; + align-self: flex-start; + + font-family: 'Unicode Symbols', 'Times New Roman', 'Apple Symbols', 'Arial Unicode MS'; +`; + +export const RightSide = styled.div` + flex-grow: 1; +`; + +export const Modifier = styled.div` + display: flex; + align-items: center; + + margin-bottom: 6px; +`; + +export const LinkedNodes = styled.div` + display: flex; + flex-direction: column; + gap: 10px; +`; diff --git a/src/components/ScnBase/components/ScnLink/ScnLink.tsx b/src/components/ScnBase/components/ScnLink/ScnLink.tsx new file mode 100644 index 0000000..0e255e0 --- /dev/null +++ b/src/components/ScnBase/components/ScnLink/ScnLink.tsx @@ -0,0 +1,39 @@ +import { ScLangText } from 'ostis-ui-lib'; +import { ScTagLink } from 'ostis-ui-lib'; +import { PseudoText } from 'ostis-ui-lib'; +import { useState } from 'react'; +import { Tooltip } from '@components/ToolTip/ToolTip'; + +export interface IScTagLinkProps { + className?: string; + addr?: number; + systemId?: string; + loaderHeight?: number | string; + loaderWidth?: number | string; +} + +export const ScnLink = ({ + addr, + systemId, + loaderHeight, + loaderWidth, + className, +}: IScTagLinkProps) => { + const [isLoad, setIsLoad] = useState(true); + + return ( + <> + {isLoad && } + + + + + + + ); +}; diff --git a/src/components/ScnBase/components/ScnLink/index.tsx b/src/components/ScnBase/components/ScnLink/index.tsx new file mode 100644 index 0000000..8dc9c75 --- /dev/null +++ b/src/components/ScnBase/components/ScnLink/index.tsx @@ -0,0 +1 @@ +export * from './ScnLink'; diff --git a/src/components/ScnBase/components/ScnSkeleton/ScnSkeleton.tsx b/src/components/ScnBase/components/ScnSkeleton/ScnSkeleton.tsx new file mode 100644 index 0000000..00f1bc1 --- /dev/null +++ b/src/components/ScnBase/components/ScnSkeleton/ScnSkeleton.tsx @@ -0,0 +1,71 @@ +import { memo } from 'react'; +import { getRandomInt } from 'ostis-ui-lib'; +import { nanoid } from 'nanoid'; + +import { Child, Item, RightSide, StyledSkeleton, Wrapper } from './styled'; + +interface ITree { + id: string; + isLink?: boolean; + modifier?: string; + children?: ITree[]; +} + +const initialTree: ITree = { + id: nanoid(5), + children: [ + { + id: nanoid(5), + modifier: nanoid(5), + children: [{ id: nanoid(5) }], + }, + { + id: nanoid(5), + modifier: nanoid(5), + children: [{ id: nanoid(5) }, { id: nanoid(5), isLink: true }], + }, + { + id: nanoid(5), + children: [{ id: nanoid(5) }], + }, + { + id: nanoid(5), + children: [{ id: nanoid(5) }], + }, + { + id: nanoid(5), + modifier: nanoid(5), + children: [{ id: nanoid(5), isLink: true }, { id: nanoid(5) }, { id: nanoid(5) }], + }, + ], +}; + +interface ISkeletonItemProps { + tree: ITree; +} + +const SkeletonItem = ({ tree }: ISkeletonItemProps) => ( + + + + {tree.modifier && } + + {tree.children?.map((child) => ( + + {(tree.children?.length || 0) > 1 && } + + + ))} + + + +); + +const ScnSkeletonWrapper = () => ( + + + {initialTree.children?.map((child) => )} + +); + +export const ScnSkeleton = memo(ScnSkeletonWrapper); diff --git a/src/components/ScnBase/components/ScnSkeleton/index.tsx b/src/components/ScnBase/components/ScnSkeleton/index.tsx new file mode 100644 index 0000000..8c95e38 --- /dev/null +++ b/src/components/ScnBase/components/ScnSkeleton/index.tsx @@ -0,0 +1 @@ +export * from './ScnSkeleton'; diff --git a/src/components/ScnBase/components/ScnSkeleton/styled.ts b/src/components/ScnBase/components/ScnSkeleton/styled.ts new file mode 100644 index 0000000..471b6f4 --- /dev/null +++ b/src/components/ScnBase/components/ScnSkeleton/styled.ts @@ -0,0 +1,38 @@ +import { Skeleton } from 'ostis-ui-lib'; +import styled, { css } from 'styled-components'; + +export const Item = styled.div` + display: flex; + gap: 4px; +`; + +export const RightSide = styled.div` + width: 100%; +`; + +export const StyledSkeleton = styled(Skeleton)<{ isArc?: boolean; isMdifier?: boolean }>` + ${({ isArc }) => + isArc && + css` + flex-shrink: 0; + + margin-top: 4px; + `} + + ${({ isMdifier }) => + isMdifier && + css` + margin-bottom: 6px; + `} +`; + +export const Wrapper = styled.div` + display: flex; + flex-direction: column; + gap: 10px; +`; + +export const Child = styled.div` + display: flex; + gap: 4px; +`; diff --git a/src/components/ScnBase/constants.ts b/src/components/ScnBase/constants.ts new file mode 100644 index 0000000..f8333cd --- /dev/null +++ b/src/components/ScnBase/constants.ts @@ -0,0 +1,23 @@ +import { ScType } from 'ts-sc-client'; + +export const arcMap = { + [ScType.EdgeUCommon.value]: { right: '↔', left: '↔' }, + [ScType.EdgeDCommon.value]: { right: '→', left: '←' }, + [ScType.EdgeAccess.value]: { right: '..∍', left: '∊..' }, + [ScType.EdgeUCommonConst.value]: { right: '⇔', left: '⇔' }, + [ScType.EdgeUCommonVar.value]: { right: '⇐⇒', left: '⇐⇒' }, + [ScType.EdgeDCommonConst.value]: { right: '⇒', left: '⇐' }, + [ScType.EdgeDCommonVar.value]: { right: '_⇒', left: '_⇐' }, + [ScType.EdgeAccessConstPosPerm.value]: { right: '∍', left: '∊' }, + [ScType.EdgeAccessConstNegPerm.value]: { right: '∌', left: '∉' }, + [ScType.EdgeAccessConstFuzPerm.value]: { right: '/∍', left: '∊/' }, + [ScType.EdgeAccessConstPosTemp.value]: { right: '~∍', left: '∊~' }, + [ScType.EdgeAccessConstNegTemp.value]: { right: '~∌', left: '∉~' }, + [ScType.EdgeAccessConstFuzTemp.value]: { right: '~/∍', left: '∊/~' }, + [ScType.EdgeAccessVarPosPerm.value]: { right: '_∍', left: '_∊' }, + [ScType.EdgeAccessVarNegPerm.value]: { right: '_∌', left: '_∉' }, + [ScType.EdgeAccessVarFuzPerm.value]: { right: '_/∍', left: '_∊/' }, + [ScType.EdgeAccessVarPosTemp.value]: { right: '_~∍', left: '_∊~' }, + [ScType.EdgeAccessVarNegTemp.value]: { right: '_~∌', left: '_∉~' }, + [ScType.EdgeAccessVarFuzTemp.value]: { right: '_~/∍', left: '_∊/~' }, +}; diff --git a/src/components/ScnBase/index.tsx b/src/components/ScnBase/index.tsx new file mode 100644 index 0000000..46f6bc7 --- /dev/null +++ b/src/components/ScnBase/index.tsx @@ -0,0 +1,2 @@ +export * from './Scn'; +export * from './constants'; diff --git a/src/components/ScnBase/mock/constants.ts b/src/components/ScnBase/mock/constants.ts new file mode 100644 index 0000000..add7142 --- /dev/null +++ b/src/components/ScnBase/mock/constants.ts @@ -0,0 +1,3 @@ +export const html = `

    максимальный класс объектов исследования’ – это ролевое отношение, указывающее в рамках предметной области на множество, являющееся максимальным классом объектов исследования данной предметной области, то есть на такое исследуемое понятие’, для которого в рамках данной предметной области не существует другого исследуемого понятия', которое бы являлось надмножеством для данного.

    `; +export const image1 = + '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'; diff --git a/src/components/ScnBase/mock/index.ts b/src/components/ScnBase/mock/index.ts new file mode 100644 index 0000000..cea950a --- /dev/null +++ b/src/components/ScnBase/mock/index.ts @@ -0,0 +1 @@ +export * from './scn'; diff --git a/src/components/ScnBase/mock/scn.ts b/src/components/ScnBase/mock/scn.ts new file mode 100644 index 0000000..9de74c5 --- /dev/null +++ b/src/components/ScnBase/mock/scn.ts @@ -0,0 +1,586 @@ +import { ScType } from 'ts-sc-client'; + +import { IScnChild, IScnNode } from '../model'; + +import { html, image1 } from './constants'; + +let ind = 0; +const getId = () => ind++; + +const getLinks = (): IScnChild => ({ + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeDCommonConst.value, + direction: 'right', + }, + { + addr: getId(), + idtf: null, + type: ScType.EdgeDCommonConst.value, + direction: 'right', + }, + ], + modifiers: [ + { + addr: getId(), + idtf: 'основной идентификатор*', + type: 3, + modifierArcs: [ + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + }, + { + addr: getId(), + idtf: 'еще один идентификатор*', + type: 3, + modifierArcs: [ + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessVarPosPerm.value, + }, + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessVarPosPerm.value, + }, + ], + }, + { + addr: getId(), + idtf: "больше - не меньше'", + type: 3, + modifierArcs: [ + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + }, + ], + linkedNodes: [ + { + addr: getId(), + content: 'База знаний Financial DK', + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + { + addr: getId(), + content: 'Financial DK knowledge base', + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + ], +}); + +const decompositionChild: IScnChild = { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'left', + }, + ], + modifiers: [ + { + addr: getId(), + idtf: 'декомпозиция раздела*', + type: 3, + modifierArcs: [ + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + }, + ], + linkedNodes: [ + { + addr: getId(), + content: null, + idtf: null, + type: ScType.NodeConstTuple.value, + contentType: null, + sourceNode: null, + targetNode: null, + children: [ + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'right', + }, + ], + modifiers: [ + { + addr: getId(), + idtf: "1'", + type: 3, + modifierArcs: [ + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + }, + ], + linkedNodes: [ + { + addr: getId(), + content: null, + idtf: 'Раздел. Предметная область бизнес процессов', + type: ScType.NodeConst.value, + children: [ + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: 'Ссылка без модификатора', + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + ], + }, + ], + contentType: null, + sourceNode: null, + targetNode: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'right', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + idtf: 'Раздел. Предметная область экономических субъектов', + type: ScType.NodeConst.value, + children: null, + contentType: null, + sourceNode: null, + targetNode: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'right', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + idtf: 'Раздел. Предметная область персон', + type: ScType.NodeConst.value, + children: null, + contentType: null, + sourceNode: null, + targetNode: null, + }, + ], + }, + ], + }, + ], +}; + +export const tree1: IScnNode = { + addr: getId(), + idtf: 'База знаний Financial DK', + type: ScType.NodeConst.value, + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + children: [ + getLinks(), + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeDCommonConst.value, + direction: 'left', + }, + ], + modifiers: [ + { + addr: getId(), + idtf: 'идентификатор*', + type: 3, + modifierArcs: [ + { + addr: getId(), + idtf: null, + content: null, + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + }, + ], + linkedNodes: [ + { + addr: 10000, + content: 'Ссылка', + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeUCommonVar.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: 'Ссылка без модификатора', + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessVarFuzTemp.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + idtf: 'Длинная дуга', + type: ScType.NodeConst.value, + children: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + idtf: 'стартовый sc-элемент', + type: ScType.NodeConst.value, + children: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: 10001, + content: null, + contentType: null, + sourceNode: { + addr: getId(), + idtf: 'Авторизованный пользователь*', + type: ScType.NodeConst.value, + content: null, + }, + targetNode: { + addr: getId(), + idtf: 'sc-модель базы знаний', + type: ScType.NodeConst.value, + content: null, + }, + idtf: null, + type: ScType.EdgeDCommonConst.value, + children: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.NodeConst.value, + children: null, + }, + ], + }, + { + arcs: [ + { + addr: getId(), + idtf: null, + type: ScType.EdgeAccessConstPosPerm.value, + direction: 'left', + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: 10001, + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.NodeStruct.value, + children: null, + }, + ], + }, + decompositionChild, + ], +}; + +export const tree2: IScnNode = { + addr: getId(), + idtf: 'База знаний Financial DK', + type: ScType.LinkConst.value, + content: 'Контент ссылки', + contentType: null, + sourceNode: null, + targetNode: null, + children: [ + { + arcs: [ + { + addr: getId(), + idtf: null, + direction: 'right', + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + idtf: 'стартовый sc-элемент', + type: ScType.NodeConst.value, + children: null, + }, + ], + }, + ], +}; + +export const tree3: IScnNode = { + addr: getId(), + idtf: 'База знаний Financial DK', + content: null, + sourceNode: { + addr: getId(), + idtf: 'Авторизованный пользователь*', + type: ScType.NodeConst.value, + content: null, + }, + targetNode: { + addr: getId(), + idtf: 'sc-модель базы знаний', + type: ScType.NodeConst.value, + content: null, + }, + type: ScType.EdgeDCommonConst.value, + contentType: null, + children: [ + { + arcs: [ + { + addr: getId(), + idtf: null, + direction: 'right', + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: null, + contentType: null, + sourceNode: null, + targetNode: null, + idtf: 'стартовый sc-элемент', + type: ScType.NodeConst.value, + children: null, + }, + ], + }, + ], +}; + +export const tree4: IScnNode = { + addr: getId(), + idtf: 'База знаний Financial DK', + content: null, + sourceNode: { + addr: getId(), + idtf: 'Авторизованный пользователь*', + type: ScType.NodeConst.value, + content: null, + }, + targetNode: { + addr: getId(), + idtf: 'sc-модель базы знаний', + type: ScType.NodeConst.value, + content: null, + }, + type: ScType.EdgeDCommonConst.value, + contentType: null, + children: [ + { + arcs: [ + { + addr: getId(), + idtf: null, + direction: 'right', + type: ScType.EdgeAccessConstPosPerm.value, + }, + ], + modifiers: null, + linkedNodes: [ + { + addr: getId(), + content: image1, + contentType: 'format_png', + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + { + addr: getId(), + content: html, + contentType: 'format_html', + sourceNode: null, + targetNode: null, + idtf: null, + type: ScType.LinkConst.value, + children: null, + }, + ], + }, + ], +}; diff --git a/src/components/ScnBase/model.ts b/src/components/ScnBase/model.ts new file mode 100644 index 0000000..b03e9bd --- /dev/null +++ b/src/components/ScnBase/model.ts @@ -0,0 +1,47 @@ +export type TLinkFormat = + | 'format_txt' + | 'format_large_txt' + | 'format_html' + | 'format_github_source_link' + | 'format_pdf' + | 'format_png' + | null; + +export interface IScnNode { + addr: number; + idtf: string | null; + type: number; + content?: string | null; + contentType?: TLinkFormat; + sourceNode?: INodeShort | null; + targetNode?: INodeShort | null; + children?: IScnChild[] | null; + struct?: IScnNode; +} + +export interface IScnChild { + arcs: IArc[]; + modifiers: IModifier[] | null; + linkedNodes: IScnNode[]; +} + +interface IArc { + addr: number; + idtf: string | null; + type: number; + direction: 'left' | 'right'; +} + +interface IModifier { + addr: number; + idtf: string | null; + type: number; + modifierArcs: INodeShort[]; +} + +interface INodeShort { + addr: number; + idtf: string | null; + type: number; + content?: string | null; +} diff --git a/src/components/ScnBase/styled.ts b/src/components/ScnBase/styled.ts new file mode 100644 index 0000000..83bc742 --- /dev/null +++ b/src/components/ScnBase/styled.ts @@ -0,0 +1,49 @@ +import { ScTag } from 'ostis-ui-lib'; +import styled from 'styled-components'; + +export const StyledScTag = styled(ScTag)` + margin-bottom: 16px; + + flex-grow: 1; + + padding-right: 6px; + + margin-right: 6px; + + cursor: auto; + + overflow: auto; + + &::-webkit-scrollbar { + width: 4px; + height: 4px; + + margin: 8px; + } + &::-webkit-scrollbar-thumb { + border-radius: 10px; + + background-color: #c0c0c0; + + margin: 8px; + } + + &::-webkit-scrollbar-track { + border-radius: 10px; + + background-color: transparent; + } +`; + +export const Inner = styled.div` + position: relative; +`; + +export const Target = styled.div` + position: absolute; + + left: 0; + bottom: 200px; + height: 1px; + width: 100%; +`; diff --git a/src/components/SearchField/SearchField.tsx b/src/components/SearchField/SearchField.tsx index c2c1f0b..697ac60 100644 --- a/src/components/SearchField/SearchField.tsx +++ b/src/components/SearchField/SearchField.tsx @@ -75,7 +75,6 @@ export const SearchField: FC = ({ className }) => { onChange={onChange} emptyMessage={emptyMessage} iconsLeft={} - autoFocus > {(options || []).map((option) => (