maintenance

This commit is contained in:
2025-09-04 20:25:15 -04:00
parent 1469c7f52f
commit e8f2df9e69
214 changed files with 8507 additions and 1836 deletions

871
bun.lock
View File

@@ -1,871 +0,0 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "webcontrolcenter-zinn-2",
"dependencies": {
"@phenixrts/sdk": "2025.2.2",
"@reduxjs/toolkit": "2.9.0",
"@techniker-me/pcast-api": "2025.1.5",
"@techniker-me/tools": "2025.0.16",
"moment": "2.30.1",
"phenix-web-proto": "2020.0.3",
"react": "19.1.1",
"react-dom": "19.1.1",
"react-redux": "9.2.0",
"react-router-dom": "7.8.2",
"styled-components": "6.1.19",
},
"devDependencies": {
"@eslint/js": "9.34.0",
"@types/node": "24.3.0",
"@types/react": "19.1.12",
"@types/react-dom": "19.1.9",
"@vitejs/plugin-react-swc": "4.0.1",
"babel-plugin-styled-components": "2.1.4",
"babel-plugin-transform-amd-to-commonjs": "1.6.0",
"eslint": "9.34.0",
"eslint-plugin-react": "7.37.5",
"eslint-plugin-react-hooks": "5.2.0",
"eslint-plugin-react-refresh": "0.4.20",
"globals": "16.3.0",
"prettier": "3.6.2",
"typescript": "5.9.2",
"typescript-eslint": "8.42.0",
"typescript-plugin-styled-components": "3.0.0",
"vite": "7.1.4",
"vite-plugin-babel": "1.3.2",
"vite-plugin-commonjs": "0.10.4",
},
},
},
"packages": {
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"@babel/compat-data": ["@babel/compat-data@7.28.0", "", {}, "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw=="],
"@babel/core": ["@babel/core@7.28.3", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.3", "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ=="],
"@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="],
"@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "^7.27.3" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.28.3", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.2" } }, "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw=="],
"@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="],
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
"@babel/traverse": ["@babel/traverse@7.28.3", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", "@babel/types": "^7.28.2", "debug": "^4.3.1" } }, "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ=="],
"@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
"@emotion/is-prop-valid": ["@emotion/is-prop-valid@1.2.2", "", { "dependencies": { "@emotion/memoize": "^0.8.1" } }, "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw=="],
"@emotion/memoize": ["@emotion/memoize@0.8.1", "", {}, "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="],
"@emotion/unitless": ["@emotion/unitless@0.8.1", "", {}, "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.9", "", { "os": "aix", "cpu": "ppc64" }, "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.9", "", { "os": "android", "cpu": "arm" }, "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.9", "", { "os": "android", "cpu": "arm64" }, "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.9", "", { "os": "android", "cpu": "x64" }, "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.9", "", { "os": "linux", "cpu": "arm" }, "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.9", "", { "os": "linux", "cpu": "ia32" }, "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.9", "", { "os": "linux", "cpu": "none" }, "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.9", "", { "os": "linux", "cpu": "x64" }, "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.9", "", { "os": "none", "cpu": "x64" }, "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.9", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.9", "", { "os": "openbsd", "cpu": "x64" }, "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.9", "", { "os": "none", "cpu": "arm64" }, "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.9", "", { "os": "sunos", "cpu": "x64" }, "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.9", "", { "os": "win32", "cpu": "x64" }, "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ=="],
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="],
"@eslint/config-array": ["@eslint/config-array@0.21.0", "", { "dependencies": { "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ=="],
"@eslint/config-helpers": ["@eslint/config-helpers@0.3.1", "", {}, "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA=="],
"@eslint/core": ["@eslint/core@0.15.2", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg=="],
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="],
"@eslint/js": ["@eslint/js@9.34.0", "", {}, "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw=="],
"@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="],
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.3.5", "", { "dependencies": { "@eslint/core": "^0.15.2", "levn": "^0.4.1" } }, "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
"@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="],
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@phenixrts/sdk": ["@phenixrts/sdk@2025.2.2", "", {}, "sha512-thxg7IE3a8qE/hk1KM6zMZcZXww54/Hy8UdR4C4J43itp4r+JfD3jKLMqrHajPazbz7IaqX8ihiMDgrmRBGI7w=="],
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.9.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@standard-schema/utils": "^0.3.0", "immer": "^10.0.3", "redux": "^5.0.1", "redux-thunk": "^3.1.0", "reselect": "^5.1.0" }, "peerDependencies": { "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" }, "optionalPeers": ["react", "react-redux"] }, "sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.32", "", {}, "sha512-QReCdvxiUZAPkvp1xpAg62IeNzykOFA6syH2CnClif4YmALN1XKpB39XneL80008UbtMShthSVDKmrx05N1q/g=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.50.0", "", { "os": "android", "cpu": "arm" }, "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.50.0", "", { "os": "android", "cpu": "arm64" }, "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.50.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.50.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.50.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.50.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.50.0", "", { "os": "linux", "cpu": "arm" }, "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.50.0", "", { "os": "linux", "cpu": "arm" }, "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.50.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.50.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ=="],
"@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.50.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.50.0", "", { "os": "linux", "cpu": "none" }, "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.50.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.50.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.50.0", "", { "os": "linux", "cpu": "x64" }, "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.50.0", "", { "os": "none", "cpu": "arm64" }, "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.50.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.50.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.50.0", "", { "os": "win32", "cpu": "x64" }, "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg=="],
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
"@swc/core": ["@swc/core@1.13.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.5", "@swc/core-darwin-x64": "1.13.5", "@swc/core-linux-arm-gnueabihf": "1.13.5", "@swc/core-linux-arm64-gnu": "1.13.5", "@swc/core-linux-arm64-musl": "1.13.5", "@swc/core-linux-x64-gnu": "1.13.5", "@swc/core-linux-x64-musl": "1.13.5", "@swc/core-win32-arm64-msvc": "1.13.5", "@swc/core-win32-ia32-msvc": "1.13.5", "@swc/core-win32-x64-msvc": "1.13.5" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ=="],
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ=="],
"@swc/core-darwin-x64": ["@swc/core-darwin-x64@1.13.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng=="],
"@swc/core-linux-arm-gnueabihf": ["@swc/core-linux-arm-gnueabihf@1.13.5", "", { "os": "linux", "cpu": "arm" }, "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ=="],
"@swc/core-linux-arm64-gnu": ["@swc/core-linux-arm64-gnu@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw=="],
"@swc/core-linux-arm64-musl": ["@swc/core-linux-arm64-musl@1.13.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ=="],
"@swc/core-linux-x64-gnu": ["@swc/core-linux-x64-gnu@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA=="],
"@swc/core-linux-x64-musl": ["@swc/core-linux-x64-musl@1.13.5", "", { "os": "linux", "cpu": "x64" }, "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q=="],
"@swc/core-win32-arm64-msvc": ["@swc/core-win32-arm64-msvc@1.13.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw=="],
"@swc/core-win32-ia32-msvc": ["@swc/core-win32-ia32-msvc@1.13.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw=="],
"@swc/core-win32-x64-msvc": ["@swc/core-win32-x64-msvc@1.13.5", "", { "os": "win32", "cpu": "x64" }, "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q=="],
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
"@swc/types": ["@swc/types@0.1.24", "", { "dependencies": { "@swc/counter": "^0.1.3" } }, "sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng=="],
"@techniker-me/pcast-api": ["@techniker-me/pcast-api@2025.1.5", "https://registry-node.techniker.me/@techniker-me/pcast-api/-/pcast-api-2025.1.5.tgz", { "dependencies": { "phenix-edge-auth": "1.2.7" } }, "sha512-2e/ufy6rUx4fm9g8RMmzYXLUd+Tq8fQvpTCUQbgf7612u/tAZtmWujs3OUK4QzdIPF1W2GuPPWI3NzObb0paog=="],
"@techniker-me/tools": ["@techniker-me/tools@2025.0.16", "https://registry-node.techniker.me/@techniker-me/tools/-/tools-2025.0.16.tgz", {}, "sha512-Ul2yj1vd4lCO8g7IW2pHkAsdeRVEUMqGpiIvSedCc1joVXEWPbh4GESW83kMHtisjFjjlZIzb3EVlCE0BCiBWQ=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
"@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="],
"@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="],
"@types/react-dom": ["@types/react-dom@19.1.9", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ=="],
"@types/stylis": ["@types/stylis@4.2.5", "", {}, "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw=="],
"@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.42.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/type-utils": "8.42.0", "@typescript-eslint/utils": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.42.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.42.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.42.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.42.0", "@typescript-eslint/types": "^8.42.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.42.0", "", { "dependencies": { "@typescript-eslint/types": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0" } }, "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.42.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.42.0", "", { "dependencies": { "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/utils": "8.42.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.42.0", "", {}, "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.42.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.42.0", "@typescript-eslint/tsconfig-utils": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.42.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.42.0", "@typescript-eslint/types": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.42.0", "", { "dependencies": { "@typescript-eslint/types": "8.42.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ=="],
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@4.0.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-beta.32", "@swc/core": "^1.13.2" }, "peerDependencies": { "vite": "^4 || ^5 || ^6 || ^7" } }, "sha512-NQhPjysi5duItyrMd5JWZFf2vNOuSMyw+EoZyTBDzk+DkfYD8WNrsUs09sELV2cr1P15nufsN25hsUBt4CKF9Q=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
"array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="],
"array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="],
"array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="],
"array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="],
"array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="],
"array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="],
"arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="],
"async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="],
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
"babel-plugin-styled-components": ["babel-plugin-styled-components@2.1.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", "@babel/helper-module-imports": "^7.22.5", "@babel/plugin-syntax-jsx": "^7.22.5", "lodash": "^4.17.21", "picomatch": "^2.3.1" }, "peerDependencies": { "styled-components": ">= 2" } }, "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g=="],
"babel-plugin-transform-amd-to-commonjs": ["babel-plugin-transform-amd-to-commonjs@1.6.0", "", { "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-Dwvn+0BM6hdLMA5sfD9QzMICo8NnqqyqCyiNeKPruAuEZDdDVWbPkPh26ckJqfL/hYIkzAvK3Zj2H/7pBzIpig=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"browserslist": ["browserslist@4.25.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg=="],
"call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="],
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"camelize": ["camelize@1.0.1", "", {}, "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001739", "", {}, "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
"css-color-keywords": ["css-color-keywords@1.0.0", "", {}, "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg=="],
"css-to-react-native": ["css-to-react-native@3.2.0", "", { "dependencies": { "camelize": "^1.0.0", "css-color-keywords": "^1.0.0", "postcss-value-parser": "^4.0.2" } }, "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
"data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="],
"data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="],
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
"define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="],
"define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="],
"doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="],
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
"electron-to-chromium": ["electron-to-chromium@1.5.212", "", {}, "sha512-gE7ErIzSW+d8jALWMcOIgf+IB6lpfsg6NwOhPVwKzDtN2qcBix47vlin4yzSregYDxTCXOUqAZjVY/Z3naS7ww=="],
"es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="],
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
"es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="],
"es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="],
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
"es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="],
"es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
"esbuild": ["esbuild@0.25.9", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.9", "@esbuild/android-arm": "0.25.9", "@esbuild/android-arm64": "0.25.9", "@esbuild/android-x64": "0.25.9", "@esbuild/darwin-arm64": "0.25.9", "@esbuild/darwin-x64": "0.25.9", "@esbuild/freebsd-arm64": "0.25.9", "@esbuild/freebsd-x64": "0.25.9", "@esbuild/linux-arm": "0.25.9", "@esbuild/linux-arm64": "0.25.9", "@esbuild/linux-ia32": "0.25.9", "@esbuild/linux-loong64": "0.25.9", "@esbuild/linux-mips64el": "0.25.9", "@esbuild/linux-ppc64": "0.25.9", "@esbuild/linux-riscv64": "0.25.9", "@esbuild/linux-s390x": "0.25.9", "@esbuild/linux-x64": "0.25.9", "@esbuild/netbsd-arm64": "0.25.9", "@esbuild/netbsd-x64": "0.25.9", "@esbuild/openbsd-arm64": "0.25.9", "@esbuild/openbsd-x64": "0.25.9", "@esbuild/openharmony-arm64": "0.25.9", "@esbuild/sunos-x64": "0.25.9", "@esbuild/win32-arm64": "0.25.9", "@esbuild/win32-ia32": "0.25.9", "@esbuild/win32-x64": "0.25.9" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
"eslint": ["eslint@9.34.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.0", "@eslint/config-helpers": "^0.3.1", "@eslint/core": "^0.15.2", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.34.0", "@eslint/plugin-kit": "^0.3.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg=="],
"eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="],
"eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="],
"eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.20", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA=="],
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="],
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
"for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="],
"functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="],
"gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
"get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
"globals": ["globals@16.3.0", "", {}, "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ=="],
"globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="],
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
"graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="],
"has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="],
"has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="],
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
"immer": ["immer@10.1.3", "", {}, "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw=="],
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
"is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="],
"is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="],
"is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="],
"is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="],
"is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="],
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
"is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="],
"is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="],
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
"is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="],
"is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="],
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
"is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="],
"is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="],
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
"is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="],
"is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="],
"is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="],
"is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="],
"is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="],
"is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="],
"is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="],
"is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="],
"is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="],
"is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="],
"isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
"iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="],
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
"jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
"json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
"jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
"loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="],
"lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
"lxiv": ["lxiv@0.2.0", "", {}, "sha512-kZfRAqtw3M5iI0oe7sc3Xuo7BMVia5eDX7iodQqUM8cTUBuE0cAQsPXVOmxyD9a3ujAmgak3Dxw0f74aGGg2/w=="],
"magic-string": ["magic-string@0.30.18", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ=="],
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
"node-releases": ["node-releases@2.0.19", "", {}, "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
"object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="],
"object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="],
"object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="],
"object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="],
"object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="],
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
"own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="],
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"pbf": ["pbf@3.1.0", "", { "dependencies": { "ieee754": "^1.1.6", "resolve-protobuf-schema": "^2.0.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-/hYJmIsTmh7fMkHAWWXJ5b8IKLWdjdlAFb3IHkRBn1XUhIYBChVGfVwmHEAV3UfXTxsP/AKfYTXTS/dCPxJd5w=="],
"phenix-edge-auth": ["phenix-edge-auth@1.2.7", "", {}, "sha512-hmIA4iKrR6Pf+EoIu/k7kxKYXkiD7I8PQL7iZb+9NkC676hCeGPZK+OsRc9uNW+fDZgZlN1qoQjBxDiT5JRe+A=="],
"phenix-web-assert": ["phenix-web-assert@2020.0.2", "", { "dependencies": { "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-WRgWqXsL1Du/ty/dq/vkooOd3e2BhLCw24vVLWmWZjM/o5TjeOhxQSMSklrDuVRamVGiEkvuQpjL8lIeP/W4TQ=="],
"phenix-web-batch-http": ["phenix-web-batch-http@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-event": "^2020.0.2", "phenix-web-global": "^2020.0.2", "phenix-web-http": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-network-connection-monitor": "^2020.0.2", "phenix-web-observable": "^2020.0.2" } }, "sha512-SG9/9RerkYcXIEH9Vk6DRosWF2229DXyeUa0hiU7jawj8xrOnAE7CMVdKcbaK4GGbZWMrT4HetIAMkqxSaHGFA=="],
"phenix-web-disposable": ["phenix-web-disposable@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-kW+x6ttFlEgjDB+d5sbqr+f72hTo95SgKLHZaW2LiLYiVNhGSiJT+AscyNWdK2uq4aNjwFVn7Wj3URuwzpudYQ=="],
"phenix-web-event": ["phenix-web-event@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-6DnrzoZ6Dfwdh5sLaAmeApxf2FgUG/7iQWJL1+IGhAcb2GJqW+JQEMQ8aWIP9lnhQTaoDP8xsAp7aieAALRmrw=="],
"phenix-web-global": ["phenix-web-global@2020.0.2", "", {}, "sha512-dBn6Ox6Nq79jx3zr/bI5K76yyCmMne/Br2XhRZ5XVXPKSYh5EMWdUBmtmaUub8Gi2Gc9gcJnq5NeiP7z8S1/6A=="],
"phenix-web-http": ["phenix-web-http@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-5/vev4Zeabmcfl6s4c5sGScGGF6qecGRyVvooex5kExDWkRpm3az04migm87+Nyb/94vYTEoRYqpwFhrrHs5pw=="],
"phenix-web-lodash-light": ["phenix-web-lodash-light@2020.0.4", "", {}, "sha512-E6xO/laCZXpmMKM/oLZrbB+uYteW4foTrybAoM82pRaLxYvevNUiZKD1xq4sIShMiWjqVv4GNOHlOp109GA/Pw=="],
"phenix-web-network-connection-monitor": ["phenix-web-network-connection-monitor@2020.0.2", "", { "dependencies": { "phenix-web-disposable": "^2020.0.2", "phenix-web-event": "^2020.0.2", "phenix-web-global": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-observable": "^2020.0.2" } }, "sha512-GizAKpSqsM48lYTAL7s/y5AKX8v3nbx2V75vTVCee2XTYV7b8SR0LnUYkkaefZXE9D+uV+WH+vXUXT9niQBJ/Q=="],
"phenix-web-observable": ["phenix-web-observable@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2" } }, "sha512-HwdBUV9LFsCa5aov/I+zyD5uFsNcsxxUmjN+3F/0gbfLNRWJlNSRGzBFQrM3UWUE/YOFnEvsEiNg90ZlXpyoKA=="],
"phenix-web-proto": ["phenix-web-proto@2020.0.3", "", { "dependencies": { "lxiv": "0.2.0", "pbf": "3.1.0", "phenix-web-assert": "^2020.0.2", "phenix-web-batch-http": "^2020.0.2", "phenix-web-disposable": "^2020.0.2", "phenix-web-event": "^2020.0.2", "phenix-web-global": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-reconnecting-websocket": "^2020.0.2" } }, "sha512-79D05OVnKOCTE8mX8his0gEtSaxWgUOsCYzwfZfSEzBk0o80n37ups2T3EfAaoVG9R0rRzWKwg1SmKpmsymxlA=="],
"phenix-web-reconnecting-websocket": ["phenix-web-reconnecting-websocket@2020.0.2", "", { "dependencies": { "phenix-web-assert": "^2020.0.2", "phenix-web-lodash-light": "^2020.0.2", "phenix-web-network-connection-monitor": "^2020.0.2" } }, "sha512-5l8AvR+8BnQZNhiyz63tuH/xFh5i01YofU6woKHxPGV+HfhJUloHU4nVoUt7vRCfPKRuDTa7bh3hJEtBnOLYag=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="],
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
"prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="],
"prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="],
"protocol-buffers-schema": ["protocol-buffers-schema@3.6.0", "", {}, "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="],
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
"react-dom": ["react-dom@19.1.1", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.1" } }, "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw=="],
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
"react-redux": ["react-redux@9.2.0", "", { "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "@types/react": "^18.2.25 || ^19", "react": "^18.0 || ^19", "redux": "^5.0.0" }, "optionalPeers": ["@types/react", "redux"] }, "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g=="],
"react-router": ["react-router@7.8.2", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ=="],
"react-router-dom": ["react-router-dom@7.8.2", "", { "dependencies": { "react-router": "7.8.2" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow=="],
"redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
"redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "^5.0.0" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
"regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="],
"reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
"resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
"resolve-protobuf-schema": ["resolve-protobuf-schema@2.1.0", "", { "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ=="],
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rollup": ["rollup@4.50.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.50.0", "@rollup/rollup-android-arm64": "4.50.0", "@rollup/rollup-darwin-arm64": "4.50.0", "@rollup/rollup-darwin-x64": "4.50.0", "@rollup/rollup-freebsd-arm64": "4.50.0", "@rollup/rollup-freebsd-x64": "4.50.0", "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", "@rollup/rollup-linux-arm-musleabihf": "4.50.0", "@rollup/rollup-linux-arm64-gnu": "4.50.0", "@rollup/rollup-linux-arm64-musl": "4.50.0", "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", "@rollup/rollup-linux-ppc64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-gnu": "4.50.0", "@rollup/rollup-linux-riscv64-musl": "4.50.0", "@rollup/rollup-linux-s390x-gnu": "4.50.0", "@rollup/rollup-linux-x64-gnu": "4.50.0", "@rollup/rollup-linux-x64-musl": "4.50.0", "@rollup/rollup-openharmony-arm64": "4.50.0", "@rollup/rollup-win32-arm64-msvc": "4.50.0", "@rollup/rollup-win32-ia32-msvc": "4.50.0", "@rollup/rollup-win32-x64-msvc": "4.50.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw=="],
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
"safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="],
"safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="],
"safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="],
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
"semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"set-cookie-parser": ["set-cookie-parser@2.7.1", "", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="],
"set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="],
"set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="],
"set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="],
"shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="],
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
"string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="],
"string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="],
"string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="],
"string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="],
"string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="],
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
"styled-components": ["styled-components@6.1.19", "", { "dependencies": { "@emotion/is-prop-valid": "1.2.2", "@emotion/unitless": "0.8.1", "@types/stylis": "4.2.5", "css-to-react-native": "3.2.0", "csstype": "3.1.3", "postcss": "8.4.49", "shallowequal": "1.1.0", "stylis": "4.3.2", "tslib": "2.6.2" }, "peerDependencies": { "react": ">= 16.8.0", "react-dom": ">= 16.8.0" } }, "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA=="],
"stylis": ["stylis@4.3.2", "", {}, "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg=="],
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="],
"tslib": ["tslib@2.6.2", "", {}, "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="],
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
"typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="],
"typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="],
"typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="],
"typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="],
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
"typescript-eslint": ["typescript-eslint@8.42.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.42.0", "@typescript-eslint/parser": "8.42.0", "@typescript-eslint/typescript-estree": "8.42.0", "@typescript-eslint/utils": "8.42.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ozR/rQn+aQXQxh1YgbCzQWDFrsi9mcg+1PM3l/z5o1+20P7suOIaNg515bpr/OYt6FObz/NHcBstydDLHWeEKg=="],
"typescript-plugin-styled-components": ["typescript-plugin-styled-components@3.0.0", "", { "peerDependencies": { "typescript": "~4.8 || 5" } }, "sha512-QWlhTl6NqsFxtJyxn7pJjm3RhgzXSByUftZ3AoQClrMMpa4yAaHuJKTN1gFpH3Ti+Rwm56fNUfG9pXSBU+WW3A=="],
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
"undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
"update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
"vite": ["vite@7.1.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw=="],
"vite-plugin-babel": ["vite-plugin-babel@1.3.2", "", { "peerDependencies": { "@babel/core": "^7.0.0", "vite": "^2.7.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-mEld4OVyuNs5+ISN+U5XyTnNcDwln/s2oER2m0PQ32YYPqPR25E3mfnhAA/RkZJxPuwFkprKWV405aZArE6kzA=="],
"vite-plugin-commonjs": ["vite-plugin-commonjs@0.10.4", "", { "dependencies": { "acorn": "^8.12.1", "magic-string": "^0.30.11", "vite-plugin-dynamic-import": "^1.6.0" } }, "sha512-eWQuvQKCcx0QYB5e5xfxBNjQKyrjEWZIR9UOkOV6JAgxVhtbZvCOF+FNC2ZijBJ3U3Px04ZMMyyMyFBVWIJ5+g=="],
"vite-plugin-dynamic-import": ["vite-plugin-dynamic-import@1.6.0", "", { "dependencies": { "acorn": "^8.12.1", "es-module-lexer": "^1.5.4", "fast-glob": "^3.3.2", "magic-string": "^0.30.11" } }, "sha512-TM0sz70wfzTIo9YCxVFwS8OA9lNREsh+0vMHGSkWDTZ7bgd1Yjs5RV8EgB634l/91IsXJReg0xtmuQqP0mf+rg=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
"which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="],
"which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="],
"which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="],
"which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="],
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
"yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"@humanfs/node/@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="],
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"fdir/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"styled-components/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="],
"tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"vite/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
}
}

View File

@@ -23,10 +23,15 @@
"react-dom": "19.1.1",
"react-redux": "9.2.0",
"react-router-dom": "7.8.2",
"styled-components": "6.1.19"
"styled-components": "6.1.19",
"uuid": "11.1.0"
},
"devDependencies": {
"@eslint/js": "9.34.0",
"@fortawesome/fontawesome-svg-core": "7.0.1",
"@fortawesome/free-regular-svg-icons": "7.0.1",
"@fortawesome/free-solid-svg-icons": "7.0.1",
"@fortawesome/react-fontawesome": "3.0.2",
"@types/node": "24.3.0",
"@types/react": "19.1.12",
"@types/react-dom": "19.1.9",
@@ -39,6 +44,8 @@
"eslint-plugin-react-refresh": "0.4.20",
"globals": "16.3.0",
"prettier": "3.6.2",
"react-datepicker": "8.7.0",
"react-toastify": "11.0.5",
"typescript": "5.9.2",
"typescript-eslint": "8.42.0",
"typescript-plugin-styled-components": "3.0.0",

View File

@@ -1,11 +1,19 @@
import {JSX} from 'react';
import React from 'react';
import styled from 'styled-components';
import Router from './routers';
import Theme from './theme';
const App = (): JSX.Element => {
const AppContainer = styled.div`
min-height: 100vh;
background: ${Theme.backgrounds.defaultBackground};
background-attachment: fixed;
`;
const App = (): React.JSX.Element => {
return (
<>
<AppContainer>
<Router />
</>
</AppContainer>
);
};

View File

@@ -1,9 +1,9 @@
import {JSX} from 'react';
import React from 'react';
import {Navigate, useLocation} from 'react-router-dom';
import {useAppSelector} from 'store';
import {selectIsAuthenticated} from 'store/slices/Authentication.slice';
export function ProtectedRoute({component}: {component: JSX.Element}): JSX.Element {
export function ProtectedRoute({component}: {component: React.JSX.Element}): React.JSX.Element {
const isAuthenticated = useAppSelector(selectIsAuthenticated);
const location = useLocation();

View File

@@ -1,7 +1,7 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {useState} from 'react';
import React, {useState} from 'react';
import {faCopy, faCheck} from '@fortawesome/free-solid-svg-icons';
import IconButton from 'components/buttons/icon-button';
@@ -9,7 +9,7 @@ import {CopyButtonContainer} from './styles';
const iconChangeTimeout = 2000;
export const CopyIconButton = (props: {text: string; quoted?: boolean; displayText?: boolean; className?: string}): JSX.Element => {
export const CopyIconButton = (props: {text: string; quoted?: boolean; displayText?: boolean; className?: string}): React.JSX.Element => {
const {text, quoted = false, displayText = true, className} = props;
const [copied, setCopied] = useState(false);
const copyToClipboard = (): void => {
@@ -22,11 +22,7 @@ export const CopyIconButton = (props: {text: string; quoted?: boolean; displayTe
return (
<CopyButtonContainer className={className}>
{displayText && (quoted ? `"${text}"` : text)}
<IconButton
onClick={copyToClipboard}
tooltipText="Copy"
icon={copied ? faCheck : faCopy}
/>
<IconButton onClick={copyToClipboard} tooltipText="Copy" icon={copied ? faCheck : faCopy} />
</CopyButtonContainer>
);
};

View File

@@ -1,6 +1,7 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {theme} from 'components/shared/theme';
import {Button} from 'components/buttons';
@@ -12,7 +13,7 @@ interface IExportFileButton {
fileName?: string;
}
export const ExportFileButton = ({label = 'Export File', file, fileName = 'file'}: IExportFileButton): JSX.Element => {
export const ExportFileButton = ({label = 'Export File', file, fileName = 'file'}: IExportFileButton): React.JSX.Element => {
const handleExport = () => {
const downloadUrl = URL.createObjectURL(new Blob([file]));
const linkTag = document.createElement('a');
@@ -24,12 +25,7 @@ export const ExportFileButton = ({label = 'Export File', file, fileName = 'file'
};
return (
<Button
onClick={handleExport}
className="testId-exportFile"
backgroundColor={colors.red}
borderColor={colors.red}
>
<Button onClick={handleExport} className="testId-exportFile" backgroundColor={colors.red} borderColor={colors.red}>
{label}
</Button>
);

View File

@@ -16,14 +16,9 @@ interface IIconButton {
className?: string;
}
const IconButton = ({
onClick,
tooltipText,
icon,
className
}: IIconButton) => (
const IconButton = ({onClick, tooltipText, icon, className}: IIconButton) => (
<Tooltip position={Position.Bottom} message={tooltipText}>
<IconButtonContainer className={`icon-button ${className}`} role="link" tabIndex={-11} onKeyDown={null} onClick={onClick}>
<IconButtonContainer className={`icon-button ${className}`} role="link" tabIndex={-11} onKeyDown={undefined} onClick={onClick}>
<FontAwesomeIcon icon={icon} />
</IconButtonContainer>
</Tooltip>

View File

@@ -1,6 +1,7 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {IconButton} from './style';
import addIcon from 'assets/images/icon/hash-plus.svg';
@@ -9,7 +10,7 @@ interface IAddButton {
className: string;
}
export const AddButton = ({onClick, className}: IAddButton): JSX.Element => (
export const AddButton = ({onClick, className}: IAddButton): React.JSX.Element => (
<IconButton onClick={onClick} className={className}>
<img src={addIcon} alt={'Add'} />
</IconButton>

View File

@@ -1,6 +1,7 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {IconButton} from './style';
import refreshIcon from 'assets/images/icon/refresh.svg';
@@ -10,7 +11,7 @@ interface IRefreshButton {
disabled?: boolean;
}
export const RefreshButton = ({onClick, disabled = false}: IRefreshButton): JSX.Element => (
export const RefreshButton = ({onClick, disabled = false}: IRefreshButton): React.JSX.Element => (
<IconButton onClick={onClick} disabled={disabled}>
<img src={refreshIcon} alt={'Refresh'} />
</IconButton>

View File

@@ -4,14 +4,14 @@
import * as styled from 'styled-components';
import {theme} from 'components/shared/theme';
const {fontSizeL, colors} = theme;
const {typography: {fontSizeL}, colors} = theme;
export const IconButton = styled.default.button`
border: none;
background-color: transparent;
font-size: ${fontSizeL};
color: ${colors.white};
opacity: ${({disabled}) => disabled ? 0.3 : 1};
cursor: ${({disabled}) => disabled ? 'not-allowed' : 'pointer'};
opacity: ${({disabled}) => (disabled ? 0.3 : 1)};
cursor: ${({disabled}) => (disabled ? 'not-allowed' : 'pointer')};
display: flex;
`;

View File

@@ -2,7 +2,7 @@
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
import Theme from 'theme';
export const Button = styled.default.button<{
backgroundColor?: string;

View File

@@ -1,15 +1,10 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {Fragment} from 'react';
import React, {Fragment} from 'react';
import {Tooltip, Position} from 'components/tooltip';
import {Label} from 'components/label';
import {
RadioGroup,
RadioWrapper,
RadioButtonContainer,
VisibleCheckBox
} from './style';
import {RadioGroup, RadioWrapper, RadioButtonContainer, VisibleCheckBox} from './style';
interface IRadioItems {
label: string;
@@ -17,13 +12,13 @@ interface IRadioItems {
tooltipMessage?: string;
tooltipPosition?: Position;
className?: string;
children?: JSX.Element;
children?: React.JSX.Element;
disabled?: boolean;
}
interface IRadioButtonGroup {
items: IRadioItems[];
handleOnChange: (value) => void;
handleOnChange: (value: string) => void;
currentValue: string;
}
@@ -32,30 +27,22 @@ const RadioButton = (props: {currentValue: string; value: string}) => {
return (
<RadioButtonContainer>
<input type="radio" readOnly={true} value={value} checked={currentValue === value}/>
<VisibleCheckBox checked={currentValue === value}><div/></VisibleCheckBox>
<input type="radio" readOnly={true} value={value} checked={currentValue === value} />
<VisibleCheckBox checked={currentValue === value}>
<div />
</VisibleCheckBox>
</RadioButtonContainer>
);
};
const RadioButtonGroup = (props: IRadioButtonGroup): JSX.Element => {
const RadioButtonGroup = (props: IRadioButtonGroup): React.JSX.Element => {
const {items, handleOnChange, currentValue} = props;
return (
<RadioGroup>
{items.map((
{
label,
value,
disabled,
tooltipPosition,
tooltipMessage,
children,
className
}: IRadioItems,
index: number
) => (
<RadioWrapper tabIndex={-1}
{items.map(({label, value, disabled, tooltipPosition, tooltipMessage, children, className}: IRadioItems, index: number) => (
<RadioWrapper
tabIndex={-1}
onKeyPress={() => null}
disabled={disabled}
className="button-container"
@@ -65,18 +52,12 @@ const RadioButtonGroup = (props: IRadioButtonGroup): JSX.Element => {
<RadioButton value={value} currentValue={currentValue} />
<Fragment>
{tooltipMessage ? (
<Tooltip position={tooltipPosition} message={tooltipMessage}>
<Label
className={className}
text={label}
/>
<Tooltip position={tooltipPosition || Position.Top} message={tooltipMessage}>
<Label className={className} text={label} />
</Tooltip>
) :
<Label
className={className}
text={label}
/>
}
) : (
<Label className={className} text={label} />
)}
{children}
</Fragment>
</RadioWrapper>

View File

@@ -2,13 +2,10 @@
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {theme, paddings} from 'components/shared/theme';
import {theme, Theme} from 'components/shared/theme';
const {
spacing,
primaryFontSize,
colors
} = theme;
const {spacing, typography: {primaryFontSize}, colors} = theme;
const paddings = Theme.paddings;
export const RadioGroup = styled.default.div`
display: flex;
@@ -18,10 +15,12 @@ export const RadioWrapper = styled.default.div<{disabled?: boolean}>`
padding: ${paddings.small};
display: flex;
${({disabled}) => disabled && styled.css`
pointer-events: none;
opacity: .5;
`}
${({disabled}) =>
disabled &&
styled.css`
pointer-events: none;
opacity: 0.5;
`}
`;
export const RadioButtonContainer = styled.default.div`
@@ -43,15 +42,17 @@ export const VisibleCheckBox = styled.default.div<{checked?: boolean}>`
height: ${primaryFontSize};
border-radius: 50%;
${({checked}) => checked && styled.css`
border: none;
background-color: ${colors.red};
${({checked}) =>
checked &&
styled.css`
border: none;
background-color: ${colors.red};
div {
background-color: ${colors.black};
width: 5px;
height: 5px;
border-radius: 50%;
}
`}
div {
background-color: ${colors.black};
width: 5px;
height: 5px;
border-radius: 50%;
}
`}
`;

View File

@@ -1,15 +1,11 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import * as styled from 'styled-components';
import {theme} from 'components/shared/theme';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {
faBackward,
faFastBackward,
faFastForward,
faForward
} from '@fortawesome/free-solid-svg-icons';
import {faBackward, faFastBackward, faFastForward, faForward} from '@fortawesome/free-solid-svg-icons';
const {colors, spacing} = theme;
const ScrollButton = styled.default.button`
@@ -30,8 +26,8 @@ const TwinButtons = styled.default.div`
flex-direction: column;
`;
export const ScrollButtons = ({current}: {current: HTMLDivElement}): JSX.Element => {
const getScrollStep = current => {
export const ScrollButtons = ({current}: {current: HTMLDivElement}): React.JSX.Element => {
const getScrollStep = (current: HTMLDivElement) => {
const tableViewHeight = current.offsetHeight;
return tableViewHeight / 2;

View File

@@ -0,0 +1,67 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState, useEffect, ChangeEvent, useCallback} from 'react';
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons';
import {documentationLinks} from 'constants/links';
import {NewTabLink} from 'components/new-tab-link';
import Input from 'components/forms/Input';
import {CopyIconButton} from 'components/buttons/copy-icon-button';
import {DialogForm, Error} from 'components/modal/modal-form-response/style';
const DeleteChannelForm = ({setIsValid, alias}: {setIsValid: (isValid: boolean) => void; alias: string}): React.JSX.Element => {
const [error, setError] = useState<string | null>(null);
const [enteredAlias, setEnteredAlias] = useState('');
const validate = useCallback((): boolean => {
if (!enteredAlias) {
setError('Please enter a channel alias');
setIsValid(false);
return false;
}
if (enteredAlias !== alias) {
setError('Entered alias does not match the channels alias');
setIsValid(false);
return false;
}
setError(null);
setIsValid(true);
return true;
}, [enteredAlias, alias, setIsValid]);
useEffect(() => {
if (enteredAlias.length) {
validate();
}
}, [enteredAlias, validate]);
const handleEnteredAlias = (event: ChangeEvent<HTMLInputElement>): void => {
if (error) {
setError(null);
}
setEnteredAlias(event.target.value);
};
return (
<DialogForm>
<h3 className="testId-deleteChannelForm">
Delete Channel <NewTabLink link={documentationLinks.deleteChannel} icon={faQuestionCircle} iconColor="black" />
</h3>
<p>To delete channel, please enter the channel alias:</p>
<strong>
<CopyIconButton text={alias} quoted />
</strong>
<Input name="alias" error={!!error} onChange={handleEnteredAlias} value={enteredAlias} />
{error && <Error className="error-text testId-displayMessage">{error}</Error>}
</DialogForm>
);
};
export default DeleteChannelForm;

View File

@@ -0,0 +1,111 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState} from 'react';
import {useDispatch} from 'react-redux';
import LoggerFactory from 'services/logger/LoggerFactory';
import {deleteChannel} from 'services/channel.service';
import {listChannels} from 'store/action/channels';
import {transformToPortalError} from 'utility/error-handler';
import {deleteChannelErrorMessages} from 'constants/error-messages';
import {MultiStepModal} from 'components/modal/multi-step-modal';
import DeleteChannelForm from './delete-channel-form';
import {FormResponse} from 'components/modal/modal-form-response';
interface IDeleteChannelModal {
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
channelId: string;
alias: string;
redirect?: () => void;
}
export const DeleteChannelModal = ({isOpen, setIsOpen, channelId, alias, redirect}: IDeleteChannelModal): React.JSX.Element => {
const logger = LoggerFactory.getLogger('components/channel-icon-menu/delete-channel/DeleteChannelModal');
const dispatch = useDispatch();
const [isFormValid, setIsFormValid] = useState(false);
const [isFetching, setIsFetching] = useState(false);
const [deleteChannelResponse, setDeleteChannelResponse] = useState<{error: string | boolean | Error; status: string | number; data?: any} | null>(null);
const handleSubmit = async () => {
if (!isFormValid) {
return;
}
try {
setIsFetching(true);
logger.info('Deleting a channel [%s][%s]', alias, channelId);
const response = await deleteChannel({channelId, alias});
logger.info('Channel [%s][%s] was successfully deleted', alias, channelId);
setDeleteChannelResponse({status: 'ok', error: false, data: response});
setIsFetching(false);
} catch (e) {
const {status, message, requestPayload, statusCode} = transformToPortalError(e);
setIsFetching(false);
const errorMessage = (deleteChannelErrorMessages as Record<string, string>)[status] || message || deleteChannelErrorMessages['default'];
setDeleteChannelResponse({
status: statusCode || 'error',
error: errorMessage
});
logger.error(`${errorMessage} [%s]`, status, requestPayload);
}
};
const handleCloseModal = (): void => {
setIsOpen(false);
};
const onDeleteSuccess = async (): Promise<void> => {
setIsOpen(false);
logger.info('Updating the list of channels after the [%s][%s] channel was deleted', alias, channelId);
await dispatch(listChannels() as any);
logger.info('The list of channels was updated successfully');
if (redirect) {
redirect();
}
};
return (
<MultiStepModal
isOpen={isOpen}
closeModal={deleteChannelResponse?.status === 'ok' ? onDeleteSuccess : handleCloseModal}
steps={[
{
title: 'Delete Channel',
component: <DeleteChannelForm alias={alias} setIsValid={setIsFormValid} />,
saveButton: {
text: 'Delete Channel',
className: 'testId-deleteChannel',
disabled: !isFormValid || isFetching,
onClick: handleSubmit
}
},
{
title: 'Delete Channel',
component: <FormResponse response={deleteChannelResponse || {error: '', status: '', data: null}} />,
cancelDisabled: true,
saveButton: {
className: 'testId-doneButton',
onClick: onDeleteSuccess
}
}
]}
/>
);
};
export default DeleteChannelModal;

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default} from './delete-channel-modal';

View File

@@ -0,0 +1,107 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState, useEffect, useCallback} from 'react';
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons';
import {CapabilitiesType} from 'constants/capabilities';
import {documentationLinks} from 'constants/links';
import {Label} from 'components/forms/label';
import Checkbox from 'components/forms/Checkbox';
import {NewTabLink} from 'components/new-tab-link';
import {Dropdown} from 'components/drop-down';
import {InputWithTags} from 'components/ui/input-with-tags';
import {DialogForm, Error, Options} from 'components/modal/modal-form-response/style';
import {Capabilities} from 'components/create-token-components';
import Theme from 'theme';
const forkChannelOption = ['force', 'additive'];
const ForkChannelForm = ({setFormData, setIsValid, channelList, alias}: {setFormData: (data: any) => void; setIsValid: (isValid: boolean) => void; channelList: any[]; alias: string}): React.JSX.Element => {
const [error, setError] = useState<string | null>(null);
const [tags, setTags] = useState<string[]>([]);
const [forkOptions, setForkOptions] = useState<string[]>([]);
const [destinationChannelId, setDestinationChannelId] = useState('');
const [selectedCapabilities, setSelectedCapabilities] = useState<any[]>([]);
const [force, additive] = forkChannelOption;
const destinationChannelsList = channelList.filter(channel => channel.alias !== alias);
const validate = useCallback((): boolean => {
if (!destinationChannelId) {
setIsValid(false);
return false;
}
setError(null);
setIsValid(true);
setFormData({
streamCapabilities: selectedCapabilities.map(({value}) => value),
streamTags: tags,
options: forkOptions,
destinationChannelId
});
return true;
}, [destinationChannelId, selectedCapabilities, tags, forkOptions, setIsValid, setFormData]);
useEffect(() => {
validate();
}, [validate]);
const handleForkOptions = (value: string) => {
if (forkOptions.indexOf(value) > -1) {
const currentForkOptions = forkOptions.filter(item => item !== value);
setForkOptions(currentForkOptions);
} else {
setForkOptions([...forkOptions, value]);
}
};
const handleSetDestinationChannelId = (channelAlias: string): void => {
const channels = channelList.filter(channel => channel.alias === channelAlias);
if (channels[0]) {
const {channelId} = channels[0];
setDestinationChannelId(channelId);
setError(null);
}
};
return (
<DialogForm>
<h3 className="testId-forkChannelForm">
Fork Channel <NewTabLink link={documentationLinks.forkChannel} icon={faQuestionCircle} iconColor="black" />
</h3>
<p>
Fork <strong>"{alias}"</strong> to destination channel:
</p>
<Dropdown
name={'alias'}
label="Destination Channel Alias"
items={destinationChannelsList}
itemKey={'alias'}
onSelect={handleSetDestinationChannelId}
className="testId-destinationChannelAlias"
/>
{error && <Error>Please select a Channel from the list</Error>}
<Capabilities
label="Capabilities:"
labelColor={Theme.colors.gray900}
iconColor={Theme.colors.gray900}
capabilitiesSetTitle={CapabilitiesType.Forking}
selectedItems={selectedCapabilities}
setSelectedItems={setSelectedCapabilities}
/>
<Label text="Options" />
<Options>
<Checkbox value={force} id={force} onChange={() => handleForkOptions(force)} checked={forkOptions.indexOf(force) > -1} label={force} />
<Checkbox value={additive} id={additive} onChange={() => handleForkOptions(additive)} checked={forkOptions.indexOf(additive) > -1} label={additive} />
</Options>
<Label htmlFor="input-tag" text="Stream Tags" />
<InputWithTags id="input-tag" onTagListChange={setTags} defaultValue={tags} />
</DialogForm>
);
};
export default ForkChannelForm;

View File

@@ -0,0 +1,113 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState} from 'react';
import {useSelector} from 'react-redux';
import LoggerFactory from 'services/logger/LoggerFactory';
import {forkChannel} from 'services/channel.service';
import {AppStore} from 'store';
import {channelsSelector} from 'store/action/channels';
import {transformToPortalError} from 'utility/error-handler';
import {forkChannelErrorMessages} from 'constants/error-messages';
import {MultiStepModal} from 'components/modal/multi-step-modal';
import ForkChannelForm from './fork-channel-form';
import {FormResponse} from 'components/modal/modal-form-response';
interface IForkChannelModal {
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
channelId: string;
alias: string;
}
export const ForkChannelModal = ({isOpen, setIsOpen, channelId, alias}: IForkChannelModal): React.JSX.Element => {
const logger = LoggerFactory.getLogger('components/channel-icon-menu/fork-channel/ForkChannelModal');
const channelsState = useSelector((state: AppStore) => channelsSelector(state));
const channelList = channelsState.channels || [];
const [formData, setFormData] = useState({
streamCapabilities: [] as string[],
streamTags: [] as string[],
options: [] as string[],
destinationChannelId: ''
});
const [isFormValid, setIsFormValid] = useState(false);
const [isFetching, setIsFetching] = useState(false);
const [forkResponse, setForkResponse] = useState<{error: string | boolean | Error; status: string | number; data?: any} | null>(null);
const handleSubmit = async () => {
if (!isFormValid) {
return;
}
try {
setIsFetching(true);
const {streamCapabilities, streamTags, options, destinationChannelId} = formData;
logger.info('Forking a channel [%s] to [%s]', channelId, destinationChannelId);
const response = await forkChannel({
sourceChannelId: channelId,
destinationChannelId,
streamCapabilities,
streamTags,
options
});
logger.info('The channel [%s] was successfully forked to [%s]', channelId, destinationChannelId);
setForkResponse({
status: 'ok',
error: false,
data: response
});
setIsFetching(false);
} catch (e) {
const {status, message, requestPayload, statusCode} = transformToPortalError(e);
setIsFetching(false);
const errorMessage = (forkChannelErrorMessages as Record<string, string>)[status] || message || forkChannelErrorMessages['default'];
setForkResponse({
status: statusCode || 'error',
error: errorMessage
});
logger.error(`${errorMessage} [%s]`, status, requestPayload);
}
};
const handleCloseModal = (): void => {
setIsOpen(false);
};
return (
<MultiStepModal
isOpen={isOpen}
closeModal={handleCloseModal}
steps={[
{
title: 'Fork Channel',
component: <ForkChannelForm alias={alias} channelList={channelList} setIsValid={setIsFormValid} setFormData={setFormData} />,
saveButton: {
text: 'Fork Channel',
className: 'testId-forkChannel',
disabled: !isFormValid || isFetching,
onClick: handleSubmit
}
},
{
title: 'Fork Channel',
component: <FormResponse response={forkResponse || {error: '', status: '', data: null}} />,
cancelDisabled: true,
saveButton: {className: 'testId-doneButton'}
}
]}
/>
);
};
export default ForkChannelModal;

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default} from './fork-channel-modal';

View File

@@ -0,0 +1,65 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState} from 'react';
import {IconDefinition} from '@fortawesome/free-solid-svg-icons';
import {IconMenu} from 'components/icon-menu';
import {IconMenuPosition} from 'components/icon-menu/types';
import ForkChannelModal from './fork-channel';
import DeleteChannelModal from './delete-channel';
import KillChannelModal from './kill-channel';
interface IChannelIconMenu {
data: {
name: string;
channelId: string;
applicationId: string;
alias: string;
};
redirect?: () => void;
showTail?: boolean;
position?: IconMenuPosition;
icon?: IconDefinition;
margin?: number;
}
export const ChannelIconMenu = (props: IChannelIconMenu): React.JSX.Element => {
const {data, icon, redirect, showTail, position, margin} = props;
const {alias, channelId} = data;
const [isForkModalOpen, setIsForkModalOpen] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isKillModalOpen, setIsKillModalOpen] = useState(false);
const items = [
{
value: 'delete',
title: 'Delete',
className: 'testId-deleteMenuItem',
onClick: () => setIsDeleteModalOpen(true)
},
{
value: 'kill',
title: 'Kill',
className: 'testId-killMenuItem',
onClick: () => setIsKillModalOpen(true)
},
{
value: 'fork',
title: 'Fork',
className: 'testId-forkMenuItem',
onClick: () => setIsForkModalOpen(true)
}
];
return (
<>
<IconMenu icon={icon} items={items} showTail={showTail} position={position} margin={margin} />
{isForkModalOpen && <ForkChannelModal isOpen={isForkModalOpen} setIsOpen={setIsForkModalOpen} channelId={channelId} alias={alias} />}
{isDeleteModalOpen && (
<DeleteChannelModal isOpen={isDeleteModalOpen} setIsOpen={setIsDeleteModalOpen} channelId={channelId} alias={alias} redirect={redirect} />
)}
{isKillModalOpen && <KillChannelModal isOpen={isKillModalOpen} setIsOpen={setIsKillModalOpen} channelId={channelId} alias={alias} />}
</>
);
};

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default} from './kill-channel-modal';

View File

@@ -0,0 +1,129 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState, useEffect, ChangeEvent, useCallback} from 'react';
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons';
import {documentationLinks} from 'constants/links';
import Checkbox from 'components/forms/Checkbox';
import {Label} from 'components/label';
import {NewTabLink} from 'components/new-tab-link';
import {DialogForm, Error, Options} from 'components/modal/modal-form-response/style';
import {CopyIconButton} from 'components/buttons/copy-icon-button';
import {Tooltip, Position} from 'components/tooltip';
import {Input} from 'components/ui';
const keepStreams = 'keep-streams';
const keepStreamsTooltipMessage = 'Keeps the removed streams alive';
const destroyRequired = 'destroy-required';
const destroyRequiredTooltipMessage = 'Returns an error if destroying of a stream fails';
const defaultReason = 'portal:killed';
const KillChannelForm = ({setFormData, setIsValid, alias}: {setFormData: (data: any) => void; setIsValid: (isValid: boolean) => void; alias: string}): React.JSX.Element => {
const [error, setError] = useState<string | null>(null);
const [enteredAlias, setEnteredAlias] = useState('');
const [reason, setReason] = useState(defaultReason);
const [options, setOptions] = useState<string[]>([]);
const validate = useCallback((): boolean => {
if (!enteredAlias) {
setError('Please enter a channel alias');
setIsValid(false);
return false;
}
if (enteredAlias !== alias) {
setError('Entered alias does not match the channels alias');
setIsValid(false);
return false;
}
setError(null);
setIsValid(true);
setFormData({
reason,
options,
enteredAlias
});
return true;
}, [enteredAlias, alias, reason, options, setIsValid, setFormData, setError]);
useEffect(() => {
if (enteredAlias.length) {
validate();
}
}, [enteredAlias, validate]);
const handleAlias = (event: ChangeEvent<HTMLInputElement>): void => {
if (error) {
setError(null);
}
setEnteredAlias(event.target.value);
};
const handleKillOptions = (value: string) => {
if (options.indexOf(value) > -1) {
const currentOptions = options.filter(item => item !== value);
setOptions(currentOptions);
} else {
setOptions([...options, value]);
}
};
const handleReason = (event: ChangeEvent<HTMLInputElement>): void => {
if (error) {
setError(null);
}
setReason(event.target.value);
};
return (
<DialogForm>
<h3 className="testId-killChannelForm">
Kill Channel <NewTabLink link={documentationLinks.killChannel} icon={faQuestionCircle} iconColor="black" />
</h3>
<p>Terminates all streams and removes them from the channel.</p>
<p>To kill the channel, please enter the channel alias:</p>
<strong>
<CopyIconButton text={alias} quoted />
</strong>
<Input error={!!error} onChange={handleAlias} value={enteredAlias} name="alias" />
{error && (
<Error className="error-text">
Please enter the channel alias <i>{alias}</i>
</Error>
)}
<h5>Kill options:</h5>
<Options>
<Tooltip position={Position.Bottom} message={keepStreamsTooltipMessage}>
<Checkbox
value={keepStreams}
id={keepStreams}
onChange={() => handleKillOptions(keepStreams)}
checked={options.indexOf(keepStreams) > -1}
label={keepStreams}
/>
</Tooltip>
<Tooltip position={Position.Bottom} message={destroyRequiredTooltipMessage}>
<Checkbox
value={destroyRequired}
id={destroyRequired}
onChange={() => handleKillOptions(destroyRequired)}
checked={options.indexOf(destroyRequired) > -1}
label={destroyRequired}
/>
</Tooltip>
</Options>
<Label htmlFor="reason" text="Reason:" />
<Input id="reason" error={!!error} onChange={handleReason} value={reason} />
</DialogForm>
);
};
export default KillChannelForm;

View File

@@ -0,0 +1,106 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState} from 'react';
import LoggerFactory from 'services/logger/LoggerFactory';
import {killChannel} from 'services/channel.service';
import {transformToPortalError} from 'utility/error-handler';
import {killChannelErrorMessages} from 'constants/error-messages';
import {MultiStepModal} from 'components/modal/multi-step-modal';
import KillChannelForm from './kill-channel-form';
import {FormResponse} from 'components/modal/modal-form-response';
interface IKillChannelModal {
isOpen: boolean;
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
channelId: string;
alias: string;
}
export const KillChannelModal = ({isOpen, setIsOpen, channelId, alias}: IKillChannelModal): React.JSX.Element => {
const logger = LoggerFactory.getLogger('components/channel-icon-menu/kill-channel/KillChannelModal');
const [formData, setFormData] = useState({
reason: '',
options: [] as string[],
enteredAlias: ''
});
const [isFormValid, setIsFormValid] = useState(false);
const [isFetching, setIsFetching] = useState(false);
const [killResponse, setKillResponse] = useState<{error: string | boolean | Error; status: string | number; data?: any} | null>(null);
const handleSubmit = async () => {
if (!isFormValid) {
return;
}
try {
setIsFetching(true);
const {reason, options} = formData;
logger.info('Killing a channel [%s] with reason [%s]', channelId, reason);
const response = await killChannel({
channelId,
reason,
options,
enteredAlias: formData.enteredAlias
});
logger.info('The channel [%s] was successfully killed', channelId);
setKillResponse({
status: 'ok',
error: false,
data: response
});
setIsFetching(false);
} catch (e) {
const {status, message, requestPayload, statusCode} = transformToPortalError(e);
setIsFetching(false);
const errorMessage = (killChannelErrorMessages as Record<string, string>)[status] || message || killChannelErrorMessages['default'];
setKillResponse({
status: statusCode || 'error',
error: errorMessage
});
logger.error(`${errorMessage} [%s]`, status, requestPayload);
}
};
const handleCloseModal = (): void => {
setIsOpen(false);
};
return (
<MultiStepModal
isOpen={isOpen}
closeModal={handleCloseModal}
steps={[
{
title: 'Kill Channel',
component: <KillChannelForm alias={alias} setIsValid={setIsFormValid} setFormData={setFormData} />,
saveButton: {
text: 'Kill Channel',
className: 'testId-killChannel',
disabled: !isFormValid || isFetching,
onClick: handleSubmit
}
},
{
title: 'Kill Channel',
component: <FormResponse response={killResponse || {error: '', status: '', data: null}} />,
cancelDisabled: true,
saveButton: {className: 'testId-doneButton'}
}
]}
/>
);
};
export default KillChannelModal;

View File

@@ -0,0 +1,62 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX, useEffect, useState} from 'react';
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons';
import {documentationLinks} from 'constants/links';
import {CapabilitiesType, capabilities} from 'constants/capabilities';
import {AdvancedSelect, IAdvancedSelectItem} from 'components/ui/advanced-select';
import {NewTabLink} from 'components/new-tab-link';
import Theme from 'theme';
interface ICapabilities {
selectedItems: IAdvancedSelectItem[];
setSelectedItems: (items: IAdvancedSelectItem[]) => void;
data?: IAdvancedSelectItem[];
label?: string;
labelColor?: string;
iconColor?: string;
capabilitiesSetTitle?: string;
className?: string;
allowMultiple?: boolean;
}
export const Capabilities = ({
label,
labelColor = Theme.colors.white,
iconColor = Theme.colors.white,
data = capabilities,
selectedItems,
setSelectedItems,
capabilitiesSetTitle = '',
className,
allowMultiple = true
}: ICapabilities): JSX.Element => {
const [capabilitiesSet, setCapabilitiesSet] = useState(data);
useEffect(() => {
const filteredCapabilities = data.filter(capability => {
return capabilitiesSetTitle ? capability.type.includes(capabilitiesSetTitle) : true;
});
setCapabilitiesSet(filteredCapabilities);
}, [capabilitiesSetTitle]);
return (
<AdvancedSelect
allowMultiple={allowMultiple}
label={label}
labelColor={labelColor}
labelIcon={capabilitiesSetTitle !== CapabilitiesType.Quality ? <NewTabLink link={documentationLinks.supportedStreamCapabilities} icon={faQuestionCircle} iconColor={iconColor} /> : undefined}
data={capabilitiesSet}
selectedItems={selectedItems}
setSelectedItems={setSelectedItems}
className={className}
/>
);
};
export default Capabilities;

View File

@@ -0,0 +1,8 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as Capabilities} from './capabilities';
export {default as ValidityTimeComponent} from './validity-time';
export * from './validity-time';
export {default as LabelIconTooltip} from './label-icon-tooltip';
export * from './styles';

View File

@@ -0,0 +1,44 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {AdvancedSelect, IAdvancedSelectItem} from '../ui/advanced-select';
import {Label} from '../forms/label';
interface CapabilitiesProps {
label: string;
labelColor?: string;
iconColor?: string;
capabilitiesSetTitle: string;
selectedItems: IAdvancedSelectItem[];
setSelectedItems: (items: IAdvancedSelectItem[]) => void;
}
export const Capabilities: React.FC<CapabilitiesProps> = ({
label,
labelColor,
iconColor,
capabilitiesSetTitle,
selectedItems,
setSelectedItems
}) => {
// Mock capabilities data - in a real app this would come from constants/capabilities
const mockCapabilities: IAdvancedSelectItem[] = [
{ value: 'streaming', text: 'Streaming' },
{ value: 'recording', text: 'Recording' },
{ value: 'analytics', text: 'Analytics' },
{ value: 'transcoding', text: 'Transcoding' }
];
return (
<div>
<Label text={label} />
<AdvancedSelect
items={mockCapabilities}
selectedItems={selectedItems}
setSelectedItems={setSelectedItems}
placeholder={`Select ${capabilitiesSetTitle} capabilities...`}
/>
</div>
);
};

View File

@@ -0,0 +1,26 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faQuestionCircle, IconDefinition} from '@fortawesome/free-solid-svg-icons';
import {Tooltip, Position} from 'components/tooltip';
interface ILabelIconTooltip {
message: string;
icon?: IconDefinition;
position?: Position;
}
export const LabelIconTooltip = ({message, icon, position}: ILabelIconTooltip): React.JSX.Element => (
<Tooltip
position={position || Position.Right}
message={message}
width={300}
>
<FontAwesomeIcon icon={icon || faQuestionCircle} />
</Tooltip>
);
export default LabelIconTooltip;

View File

@@ -0,0 +1,60 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {theme} from 'components/shared/theme';
import {RadioGroup} from 'components/buttons/radio-button/style';
// import Input from 'components/forms/Input';
const {
spacing,
colors
} = theme;
export const CreateTokenContainer = styled.default.div`
margin: 0.5rem 0 0;
`;
export const FormWell = styled.default.div`
display: flex;
flex-wrap: wrap;
width: 100%;
`;
export const RadioButtonContainer = styled.default.div`
display: flex;
flex-direction: column;
margin-top: ${spacing.small} 0;
label {
font-size: 14px;
color: ${colors.white};
}
${RadioGroup}{
flex-direction: column;
.reason-input {
display: flex;
flex-grow: 1;
}
}
`;
export const InputGroup = styled.default.div`
margin: 0 1rem 1rem 0;
input {
width: 200px;
padding-left: ${spacing.small};
}
> label {
display: block;
}
select {
width: 200px;
}
`;
export const RowsWrapper = styled.default.div`
width: 100%;
display: flex;
justify-content: space-between;
`;

View File

@@ -0,0 +1,60 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {Fragment} from 'react';
import moment from 'moment';
import {ISelectItemWithClassOptions} from 'interfaces';
import RadioButtonGroup from 'components/buttons/radio-button';
import {Label} from 'components/label';
import {RadioButtonContainer} from '.';
export const validityTimeOptions: ISelectItemWithClassOptions<string> = {
hour: {
label: '1 Hour',
value: `${moment.duration(1, 'hour').asSeconds()}`
},
day: {
label: '1 Day',
value: `${moment.duration(1, 'day').asSeconds()}`
},
week: {
label: '1 Week',
value: `${moment.duration(1, 'week').asSeconds()}`
},
month: {
label: '1 Month',
value: `${moment.duration(1, 'month').asSeconds()}`
},
year: {
label: '1 Year',
value: `${moment.duration(1, 'year').asSeconds()}`
},
decade: {
label: '10 Years',
value: `${moment.duration(10, 'year').asSeconds()}`
}
};
interface IValidityTimeComponent {
onChange: (value: string) => void;
currentValue: string;
}
export const ValidityTimeComponent = ({currentValue, onChange}: IValidityTimeComponent): React.JSX.Element => (
<Fragment>
<Label text="Valid For:" color="white" />
<RadioButtonContainer className="testId-expirationTime">
<RadioButtonGroup
items={Object.values(validityTimeOptions)}
currentValue={currentValue}
handleOnChange={onChange}
/>
</RadioButtonContainer>
</Fragment>
);
export default ValidityTimeComponent;

View File

@@ -0,0 +1,51 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX, useEffect, useState} from 'react';
import {useSelector} from 'react-redux';
import {Moment} from 'moment';
import {AppStore} from 'store';
import {getTimezoneAbbreviation, isoTimeFormat} from 'utility/date';
export const DateComponent = ({
date,
className
}: {
date: Moment;
className?: string;
}): JSX.Element => {
const preferredTimeFormat = useSelector((state: AppStore) => state.preferredTimeFormat.timeFormat);
const isUTC = preferredTimeFormat === 'utc';
const utcDate = date.isValid() ? date.format(`${isoTimeFormat} UTC`) : '';
const localDate = date.isValid() ? `${date.clone().local().format(isoTimeFormat)} ${getTimezoneAbbreviation(date.toDate())}` : '';
const defaultDate = isUTC ? utcDate : localDate;
const hoverDate = isUTC ? localDate : utcDate;
const [currentDate, setCurrentDate] = useState(defaultDate);
useEffect(() => {
setCurrentDate(defaultDate);
}, [date, preferredTimeFormat]);
const onMouseEnter = () => {
setCurrentDate(hoverDate);
};
const onMouseOut = () => {
setCurrentDate(defaultDate);
};
const onBlur = () => {
setCurrentDate(defaultDate);
};
return (
<p
onMouseEnter={onMouseEnter}
onMouseOut={onMouseOut}
onBlur={onBlur}
className={className}
>
{currentDate}
</p>
);
};

View File

@@ -0,0 +1,212 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState, useEffect, useRef} from 'react';
import {IChannel} from 'interfaces';
import {Label} from 'components/label';
import {DropdownContainer, DropdownInput, DropdownMenu, DropdownMenuItem} from './style';
const keys = ['ArrowDown', 'ArrowUp', 'Enter', 'Escape'];
interface IDropdown {
itemKey: string;
searchTerm?: string;
onSelect: (key: string) => void;
items: IChannel[];
label: string;
name: string;
className?: string;
}
const maxNumOfItemsShown = 30;
export const Dropdown = (props: IDropdown): React.JSX.Element => {
const {itemKey, searchTerm, onSelect, items, label, name, className} = props;
const [showDropdownMenu, setShowDropdownMenu] = useState(false);
const [input, setInput] = useState(searchTerm || '');
const [filteredItems, setFilteredItems] = useState(items);
const [selectedIndex, setSelectedIndex] = useState(0);
const allItemsRef = useRef<any[]>([]);
const parentElementRef = useRef<HTMLDivElement | null>(null);
const scrollSelectedItemInView = (index: number) => {
if (!parentElementRef.current) {
return;
}
const dropdownMenu = parentElementRef.current;
const menuItems = allItemsRef.current;
if (!menuItems) {
return;
}
const menuItem = menuItems[index];
if (!menuItem) {
return;
}
const isOutOfUpperView = menuItem.offsetTop < dropdownMenu.scrollTop;
const isOutOfLowerView = (menuItem.offsetTop + menuItem.clientHeight) > (dropdownMenu.scrollTop + dropdownMenu.clientHeight);
if (isOutOfUpperView) {
dropdownMenu.scrollTop = menuItem.offsetTop;
} else if (isOutOfLowerView) {
dropdownMenu.scrollTop = (menuItem.offsetTop + menuItem.clientHeight) - dropdownMenu.clientHeight;
}
};
const setSelectInput = (value: string) => {
setInput(value);
onSelect(value);
};
const handleClickOutside = (event: MouseEvent) => {
if (!parentElementRef.current || parentElementRef.current.contains(event.target as Node)) {
return;
}
if (!filteredItems.length) {
setSelectInput('');
}
setShowDropdownMenu(false);
onSelect(input);
};
useEffect(() => {
scrollSelectedItemInView(selectedIndex);
}, [selectedIndex]);
useEffect(() => {
document.addEventListener('click', handleClickOutside, true);
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
});
useEffect(() => {
const filteredItems = items.filter(item => {
if ((item as any)[itemKey].toLowerCase().indexOf(input.toLowerCase()) > -1) {
return true;
}
return false;
});
if (filteredItems.length > 0) {
setSelectedIndex(0);
}
setFilteredItems(filteredItems);
}, [input, items, itemKey]);
const selectItemInFocusBy = (offset: number) => {
const lastIndex = filteredItems.length - 1;
const nextIndex = selectedIndex + offset;
if (nextIndex > lastIndex) {
setSelectedIndex(0);
} else if (nextIndex < 0) {
setSelectedIndex(lastIndex);
} else {
setSelectedIndex(nextIndex);
}
};
const handleOnKeyDown = (event: React.KeyboardEvent) => {
if (keys.indexOf(event.key) === -1) {
return;
}
const [arrDown, arrUp, enter, escape] = keys;
const moves = {
[arrDown]: 1,
[arrUp]: -1
};
const move = moves[event.key];
if (move !== undefined) {
event.preventDefault();
selectItemInFocusBy(move);
}
if (event.key === enter) {
if (filteredItems[selectedIndex]) {
setSelectInput((filteredItems[selectedIndex] as any)[itemKey]);
setShowDropdownMenu(false);
}
}
if (event.key === escape) {
event.preventDefault();
setShowDropdownMenu(false);
}
};
const selectItem = (index: number) => {
setSelectInput((filteredItems[index] as any)[itemKey]);
setSelectedIndex(index);
setShowDropdownMenu(false);
};
const generateMenuOptions = () => {
return filteredItems.length
? filteredItems.slice(0, maxNumOfItemsShown).map((item, index) => {
return (
<DropdownMenuItem
ref={ref => {
allItemsRef.current[index] = ref;
}}
selected={selectedIndex === index}
key={`dropdown-menu-item-${index}`}
onClick={() => selectItem(index)}
>
{(item as any)[itemKey]}
</DropdownMenuItem>
);
})
: (
<DropdownMenuItem disabled={true}>
No results found
</DropdownMenuItem>
);
};
const handleInput = (event: React.ChangeEvent<HTMLInputElement>) => {
const {target} = event;
setInput(target.value);
if (!showDropdownMenu) {
setShowDropdownMenu(true);
}
};
const toggleDropdownMenu = () => setShowDropdownMenu(!showDropdownMenu);
return (
<DropdownContainer>
<Label
htmlFor="autocomplete"
text={label}
/>
<DropdownInput
onKeyDown={handleOnKeyDown}
showMenu={showDropdownMenu}
autoComplete="off"
name={name}
onChange={handleInput}
value={input}
onClick={toggleDropdownMenu}
className={className}
/>
{showDropdownMenu && (
<DropdownMenu ref={parentElementRef} className="testId-generatedMenuOptions">
{generateMenuOptions()}
</DropdownMenu>
)}
</DropdownContainer>
);
};

View File

@@ -0,0 +1,59 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Input from 'components/forms/Input';
import Theme from 'theme';
const {spacing, colors, typography, primaryBorderRadius} = Theme;
export const DropdownContainer = styled.default.div`
width: 100%;
position: relative;
margin: ${spacing.xSmall} 0;
`;
export const DropdownInput = styled.default(Input)<{showMenu?: boolean}>`
${({showMenu}) => showMenu && styled.css`
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
border-bottom-width: 0;
`}
`;
export const DropdownMenu = styled.default.div`
width: 100%;
overflow-x: hidden;
overflow-y: auto;
top: calc(100% - 4px);
position: absolute;
height: auto;
max-height: 210px;
border: 1px solid ${colors.gray400};
border-top-width: 0;
z-index: 4;
background-color: ${colors.white};
border-bottom-left-radius: ${primaryBorderRadius};
border-bottom-right-radius: ${primaryBorderRadius};
`;
export const DropdownMenuItem = styled.default.div<{
active?: boolean;
disabled?: boolean;
selected?: boolean;
}>`
line-height: ${spacing.large};
padding: ${spacing.xsmall} ${spacing.medium};
font-size: ${typography.fontSizeS};
word-wrap: break-word;
${({active, selected, disabled}) => styled.css`
background-color: ${active || selected ? colors.gray300 : 'transparent'};
font-weight: ${selected ? 'bold' : 'normal'};
color: ${disabled ? colors.gray500 : colors.gray900}
:hover{
background-color: ${disabled ? colors.white : colors.gray300};
cursor: ${disabled ? 'text' : 'pointer'};
}
`}
`;

View File

@@ -0,0 +1,12 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {toast} from 'react-toastify';
export const toastErrorRenderer = (error: string): void => {
toast.error(String(error), {
autoClose: 10000,
draggable: false,
hideProgressBar: true
});
};

View File

@@ -0,0 +1,23 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
const {headerAllowance, dangerColor, typography} = Theme;
export const Error = styled.default.div`
height: ${window.innerHeight - headerAllowance}px;
width: 100%;
display: grid;
align-content: center;
justify-content: center;
text-align: center;
color: ${dangerColor};
font-size: ${typography.fontSizeL};
`;
export const ErrorSubMessage = styled.default.div`
font-size: ${typography.fontSizeS};
color: ${dangerColor};
`;

View File

@@ -0,0 +1,83 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {ChangeEvent, MouseEvent} from 'react';
import styled from 'styled-components';
import {Label} from 'components/label';
import {theme} from 'components/shared/theme';
const {colors, spacing} = theme;
const Container = styled.div`
display: flex;
flex-direction: row;
align-items: center;
label {
margin-left: ${spacing.xxSmall};
margin-right: ${spacing.xxSmall};
}
`;
const CheckboxContainer = styled.div`
display: inline-block;
vertical-align: middle;
outline: none;
height: 1rem;
`;
const Icon = styled.svg`
fill: none;
stroke: ${colors.black};
stroke-width: 2px;
`;
const HiddenCheckbox = styled.input.attrs({type: 'checkbox'})`
border: 0;
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
`;
const StyledCheckbox = styled.div<{checked?: boolean}>`
display: inline-block;
width: 1rem;
height: 1rem;
background: ${({checked}) => checked ? colors.red : colors.transparent};
border-radius: 3px;
transition: all 150ms;
outline: none;
border: 1px solid ${({checked}) => checked ? 'none' : colors.gray400};
${Icon} {
visibility: ${({checked}) => checked ? 'visible' : 'hidden'}
}
`;
const Checkbox = (
props: {
value: string;
id?: string;
checked?: boolean;
onChange: (event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLDivElement>) => void;
label?: string;
}
): React.JSX.Element => {
const {checked, onChange, label, id} = props;
return (
<Container>
<CheckboxContainer>
<HiddenCheckbox {...props}/>
<StyledCheckbox onClick={onChange} checked={checked}>
<Icon viewBox="0 0 24 24">
<polyline points="20 6 9 17 4 12" />
</Icon>
</StyledCheckbox>
</CheckboxContainer>
{label && <Label htmlFor={id || label} text={label} />}
</Container>
);
};
export default Checkbox;

View File

@@ -0,0 +1,88 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {ChangeEvent} from 'react';
import styled from 'styled-components';
import {theme} from 'components/shared/theme';
const CheckboxContainer = styled.div`
display: flex;
align-items: center;
margin-bottom: ${theme.spacing.small};
`;
const HiddenCheckbox = styled.input.attrs({type: 'checkbox'})`
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
`;
const StyledCheckbox = styled.div<{checked: boolean}>`
display: inline-block;
width: 16px;
height: 16px;
background: ${props => (props.checked ? theme.colors.red : theme.colors.white)};
border: 2px solid ${theme.colors.gray400};
border-radius: 3px;
transition: all 150ms;
cursor: pointer;
margin-right: ${theme.spacing.small};
&::after {
content: '';
position: relative;
display: ${props => (props.checked ? 'block' : 'none')};
left: 3px;
top: 0px;
width: 4px;
height: 8px;
border: solid ${theme.colors.white};
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
`;
const Label = styled.label`
cursor: pointer;
color: ${theme.colors.gray900};
font-size: ${theme.typography.primaryFontSize};
user-select: none;
`;
interface CheckboxProps {
id: string;
checked: boolean;
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
label?: string;
value?: string;
disabled?: boolean;
className?: string;
}
const Checkbox: React.FC<CheckboxProps> = ({
id,
checked,
onChange,
label,
value,
disabled = false,
className
}) => {
return (
<CheckboxContainer className={className}>
<HiddenCheckbox
id={id}
checked={checked}
onChange={onChange}
value={value}
disabled={disabled}
/>
<StyledCheckbox checked={checked} />
{label && <Label htmlFor={id}>{label}</Label>}
</CheckboxContainer>
);
};
export default Checkbox;

View File

@@ -1,58 +1,48 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {ChangeEvent, forwardRef, ForwardedRef, InputHTMLAttributes} from 'react';
import React, {ChangeEvent, forwardRef, ForwardedRef, InputHTMLAttributes} from 'react';
import * as styled from 'styled-components';
import Theme from 'theme';
import {Label} from '../label';
import {Label} from './label';
export interface IInput extends InputHTMLAttributes<HTMLInputElement> {
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
error?: boolean;
icon?: JSX.Element;
icon?: React.JSX.Element;
imagePath?: string;
imageAltText?: string;
label?: string;
labelColor?: string;
labelIcon?: JSX.Element;
labelIcon?: React.JSX.Element;
labelClassName?: string;
helperText?: string;
helperTextClassName?: string;
width?: number | string;
}
const {
colors,
typography,
formFieldWidth,
formFieldMaxWidth,
primaryBorderColor,
primaryBorderRadius,
primaryInputHeight,
inputIconWidth,
spacing
} = Theme;
const {colors, typography, formFieldWidth, formFieldMaxWidth, primaryBorderColor, primaryBorderRadius, primaryInputHeight, inputIconWidth, spacing} = Theme;
export const InputElement = styled.default.input<IInput>`
background-color: ${colors.white};
border: 1px solid ${({error}) => error ? colors.lightRed : primaryBorderColor};
border: 1px solid ${({error}) => (error ? colors.lightRed : primaryBorderColor)};
border-radius: ${primaryBorderRadius};
display: block;
font-size: ${typography.primaryFontSize};
height: ${primaryInputHeight};
line-height: ${typography.primaryLineHeight};
outline: none;
padding: ${spacing.small} ${({icon, imagePath}) => (icon || imagePath) ? spacing.xlarge : spacing.small};
padding: ${spacing.small} ${({icon, imagePath}) => (icon || imagePath ? spacing.xlarge : spacing.small)};
transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
background-position: 1rem center;
background-repeat: no-repeat;
width: inherit;
opacity: ${({disabled}) => disabled ? 0.8 : 1};
opacity: ${({disabled}) => (disabled ? 0.8 : 1)};
cursor: ${({disabled}) => disabled && 'not-allowed'};
-webkit-text-fill-color: ${({disabled}) => disabled && colors.gray800};
`;
const HelperText = styled.default.p<IInput>`
color: ${({error}) => error ? colors.lightRed : colors.gray600};
color: ${({error}) => (error ? colors.lightRed : colors.gray600)};
font-weight: 400;
font-size: ${typography.fontSizeS};
margin-top: ${spacing.xxSmall};
@@ -79,56 +69,49 @@ const InputWrapper = styled.default.div`
export const InputComponentWrapper = styled.default.div<IInput>`
position: relative;
width: ${({width}) => width && isNaN(+width) ? width : ((width || formFieldWidth) + 'px')};
width: ${({width}) => (width && isNaN(+width) ? width : (width || formFieldWidth) + 'px')};
max-width: ${formFieldMaxWidth}px;
display: flex;
flex-direction: column;
`;
export const InputComponent = forwardRef((
{
label,
labelColor,
labelIcon,
labelClassName,
icon,
imagePath,
imageAltText = '',
helperText,
helperTextClassName,
error,
width,
disabled,
name,
...props
}: IInput, ref: ForwardedRef<HTMLInputElement>): JSX.Element => {
const InputIcon = icon || (imagePath && <img src={imagePath} alt={imageAltText} />);
export const InputComponent = forwardRef(
(
{
label,
labelColor,
labelIcon,
labelClassName,
icon,
imagePath,
imageAltText = '',
helperText,
helperTextClassName,
error,
width,
disabled,
name,
...props
}: IInput,
ref: ForwardedRef<HTMLInputElement>
): React.JSX.Element => {
const InputIcon = icon || (imagePath && <img src={imagePath} alt={imageAltText} />);
return (
<InputComponentWrapper width={width}>
{!!label && (
<Label
text={label}
color={labelColor}
icon={labelIcon}
className={labelClassName}
/>
)}
<InputWrapper>
<ImageWrapper>
{InputIcon}
</ImageWrapper>
<InputElement
icon={icon}
name={name}
imagePath={imagePath}
disabled={disabled}
ref={ref}
{...props}
/>
</InputWrapper>
{!!helperText && <HelperText className={helperTextClassName} error={error}>{helperText}</HelperText>}
</InputComponentWrapper>
);
});
return (
<InputComponentWrapper width={width}>
{!!label && <Label text={label} color={labelColor} icon={labelIcon} className={labelClassName} />}
<InputWrapper>
<ImageWrapper>{InputIcon}</ImageWrapper>
<InputElement icon={icon} name={name} imagePath={imagePath} disabled={disabled} ref={ref} {...props} />
</InputWrapper>
{!!helperText && (
<HelperText className={helperTextClassName} error={error}>
{helperText}
</HelperText>
)}
</InputComponentWrapper>
);
}
);
export default InputComponent;
export const Input = InputComponent;

View File

@@ -0,0 +1,77 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {JSX, useState, useEffect, ChangeEvent} from 'react';
import moment from 'moment';
import {IInput} from './Input';
import Input from './Input';
import Theme from 'theme';
import searchImage from 'assets/images/search-150x150.png';
const searchWaitTimeout = moment.duration(1, 'seconds').asMilliseconds();
interface ISearchInput extends IInput {
search: (str: string) => void;
defaultValue?: string;
minLengthForSearch?: number;
}
const SearchInput = styled.default(Input)`
min-width: 100%;
padding-left: ${Theme.spacing.xlarge};
`;
export const SearchInputWrapper = styled.default.div`
position: relative;
display: flex;
& div {
width: 100%;
position: relative;
align-self: center;
& img {
width: 1rem;
height: 1rem;
top: 50%;
transform: translateY(-50%);
left: 0.5rem;
position: absolute;
}
}
`;
export const Search = ({
search,
defaultValue = '',
minLengthForSearch = 2
}: ISearchInput): JSX.Element => {
const [currentSearchTerm, setCurrentSearchTerm] = useState<string>(defaultValue);
const onChange = (event: ChangeEvent<HTMLInputElement>): void => {
setCurrentSearchTerm(event.target.value);
};
useEffect(() => {
let timeout = null;
if (currentSearchTerm.length >= minLengthForSearch || currentSearchTerm.length === 0) {
timeout = setTimeout(() => search(currentSearchTerm), searchWaitTimeout);
}
return () => {
if (timeout) {
clearInterval(timeout);
}
};
}, [currentSearchTerm, minLengthForSearch, search]);
return (
<SearchInputWrapper>
<div className="search-bar">
<img src={searchImage} alt={'searchImage'} />
<SearchInput value={currentSearchTerm} onChange={onChange} name="testId-search" />
</div>
</SearchInputWrapper>
);
};
export default Search;

View File

@@ -0,0 +1 @@
export * from './label';

View File

@@ -1,23 +1,19 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX} from 'react';
import React from 'react';
import {Label as StyledLabel} from './style';
interface ILabel {
text: string;
htmlFor?: string;
color?: string;
icon?: JSX.Element;
icon?: React.JSX.Element;
className?: string;
}
export const Label = ({text, htmlFor, color, icon, className}: ILabel): JSX.Element => (
<StyledLabel
className={className}
htmlFor={htmlFor}
color={color}
>
export const Label = ({text, htmlFor, color, icon, className}: ILabel): React.JSX.Element => (
<StyledLabel className={className} htmlFor={htmlFor} color={color}>
{text} {icon}
</StyledLabel>
);

View File

@@ -8,7 +8,7 @@ const {spacing, colors, typography} = Theme;
export const Label = styled.default.label<{color?: string}>`
font-size: ${typography.fontSizeS};
color: ${({color}) => (color || colors.gray900)};
color: ${({color}) => color || colors.gray900};
font-weight: bold;
margin: ${spacing.xxSmall} 0;
display: block;

View File

@@ -0,0 +1,198 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useEffect, useRef, useState, ReactNode} from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {IconDefinition, IconProp} from '@fortawesome/fontawesome-svg-core';
import {useComponentVisible, useCurrentWidth} from 'utility/custom-hooks';
import {IconMenuWrapper, IconMenuDropDownWrapper, IconMenuContent, IconMenuPointer, DropdownIcon, IconMenuDropDownItem} from './style';
import {IconMenuPosition, defaultArrowWidth, defaultArrowEdgeGap} from './types';
interface IIconMenuItems {
title: string;
value: string;
className?: string;
onSelect?: () => void;
onClick?: () => void;
modal?: {
component: ReactNode;
action?: () => void;
};
}
interface IMenuPointerStyle {
left?: number | string;
right?: number | string;
top?: number | string;
bottom?: number | string;
width?: number | string;
height?: number | string;
}
interface IIconMenu {
items: IIconMenuItems[];
icon?: IconDefinition | IconProp;
iconClassName?: string;
iconColor?: string;
title?: string;
menuVisible?: boolean;
showTail?: boolean;
position?: IconMenuPosition;
hasPointer?: boolean;
dropdownMargin?: number;
margin?: number | string;
disabled?: boolean;
}
const IconMenu = ({
items = [],
icon,
iconClassName,
iconColor = 'white',
menuVisible = false,
title,
showTail = true,
position = IconMenuPosition.BottomLeft,
hasPointer = true,
dropdownMargin = 0,
margin,
disabled
}: IIconMenu): React.JSX.Element => {
const dropdownRef = useRef<HTMLDivElement>(null);
const [dropdownStyle, setDropdownStyle] = useState<any>(null);
const [menuPointerStyle, setMenuPointerStyle] = useState<IMenuPointerStyle>({
right: -defaultArrowWidth / 2,
top: '50%'
});
const {ref, isComponentVisible, setIsComponentVisible} = useComponentVisible(menuVisible);
const width = useCurrentWidth();
useEffect(() => {
if (!isComponentVisible) {
setDropdownStyle(null);
}
}, [isComponentVisible]);
useEffect(() => {
if (ref.current && dropdownRef.current && isComponentVisible && position) {
const refRect = (ref.current as HTMLElement).getBoundingClientRect();
const dropdownRefRect = (dropdownRef.current as HTMLElement).getBoundingClientRect();
const newArrowPosition: IMenuPointerStyle = {
width: `${defaultArrowWidth}px`,
height: `${defaultArrowWidth}px`
};
const pointerMargin = Math.sqrt((defaultArrowWidth * defaultArrowWidth) / 2);
let top = 0;
let left = 0;
switch (position) {
case IconMenuPosition.Right: {
newArrowPosition.top = `calc(50% - ${defaultArrowWidth / 2}px)`;
newArrowPosition.left = `-${defaultArrowWidth / 2}px`;
top = refRect.top + refRect.height / 2 - dropdownRefRect.height / 2;
left = refRect.left + refRect.width + pointerMargin + dropdownMargin;
break;
}
case IconMenuPosition.Top: {
newArrowPosition.left = '50%';
newArrowPosition.bottom = `-${defaultArrowWidth / 2}px`;
top = refRect.top - dropdownRefRect.height - pointerMargin - dropdownMargin;
left = refRect.left + refRect.width / 2 - dropdownRefRect.width / 2;
break;
}
case IconMenuPosition.TopLeft: {
newArrowPosition.right = `${defaultArrowEdgeGap}px`;
newArrowPosition.bottom = `-${defaultArrowWidth / 2}px`;
top = refRect.top - dropdownRefRect.height - pointerMargin - dropdownMargin;
left = refRect.left + refRect.width / 2 - dropdownRefRect.width + defaultArrowWidth / 2 + defaultArrowEdgeGap;
break;
}
case IconMenuPosition.TopRight: {
newArrowPosition.left = `${defaultArrowEdgeGap}px`;
newArrowPosition.bottom = `-${defaultArrowWidth / 2}px`;
top = refRect.top - dropdownRefRect.height - pointerMargin - dropdownMargin;
left = refRect.left + refRect.width / 2 - defaultArrowWidth / 2 - defaultArrowEdgeGap;
break;
}
case IconMenuPosition.Bottom: {
newArrowPosition.left = '50%';
newArrowPosition.top = `-${defaultArrowWidth / 2}px`;
top = refRect.top + refRect.height + pointerMargin + dropdownMargin;
left = refRect.left + refRect.width / 2 - dropdownRefRect.width / 2;
break;
}
case IconMenuPosition.BottomLeft: {
newArrowPosition.right = `${defaultArrowEdgeGap}px`;
newArrowPosition.top = `-${defaultArrowWidth / 2}px`;
top = refRect.top + refRect.height + pointerMargin + dropdownMargin;
left = refRect.left + refRect.width / 2 - dropdownRefRect.width + defaultArrowWidth / 2 + defaultArrowEdgeGap;
break;
}
case IconMenuPosition.BottomRight: {
newArrowPosition.left = `${defaultArrowEdgeGap}px`;
newArrowPosition.top = `-${defaultArrowWidth / 2}px`;
top = refRect.top + refRect.height + pointerMargin + dropdownMargin;
left = refRect.left + refRect.width / 2 - defaultArrowWidth / 2 - defaultArrowEdgeGap;
break;
}
case IconMenuPosition.Left:
default: {
newArrowPosition.top = `calc(50% - ${defaultArrowWidth / 2}px)`;
newArrowPosition.right = `-${defaultArrowWidth / 2}px`;
top = refRect.top + refRect.height / 2 - dropdownRefRect.height / 2;
left = refRect.left - dropdownRefRect.width - pointerMargin - dropdownMargin;
}
}
setDropdownStyle({
top,
left
});
setMenuPointerStyle(newArrowPosition);
}
}, [isComponentVisible, ref, position, dropdownMargin, width]);
const handleClickIcon = () => {
setIsComponentVisible(!isComponentVisible);
};
return (
<>
<IconMenuWrapper ref={ref} margin={margin}>
<DropdownIcon role="button" tabIndex={0} onClick={handleClickIcon} className={`testId-dropdownIcon ${iconClassName} ${disabled && 'disabled'}`}>
{title}
{icon && <FontAwesomeIcon icon={icon} color={iconColor} size="lg" />}
</DropdownIcon>
{isComponentVisible && (
<IconMenuDropDownWrapper ref={dropdownRef} visible={isComponentVisible && !!dropdownStyle} showTail={showTail} style={dropdownStyle || undefined}>
<IconMenuContent className="testId-dropdownItems">
{!!hasPointer && <IconMenuPointer style={menuPointerStyle} />}
{items.map((item, i) => (
<IconMenuDropDownItem key={`${item.value}-${i}`} className={item.className} onMouseUp={item.onClick} data-value={item.value}>
{item.title}
</IconMenuDropDownItem>
))}
</IconMenuContent>
</IconMenuDropDownWrapper>
)}
</IconMenuWrapper>
</>
);
};
export default IconMenu;

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as IconMenu} from './icon-menu';

View File

@@ -0,0 +1,79 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
import caretUp from 'assets/images/caret-up.svg';
const {colors, spacing} = Theme;
export const IconMenuWrapper = styled.default.div<{margin?: number | string}>`
margin: ${({margin}) => (margin !== undefined ? margin : '.5rem 0 .5rem 1rem')};
div {
outline: none;
}
& img{
width: 24px;
height: 24px;
cursor: pointer;
}
`;
export const IconMenuDropDownWrapper = styled.default.div<{showTail?: boolean; visible?: boolean}>`
position: fixed;
width: 200px;
min-height: 31px;
right: 2.5rem;
${({showTail}) =>
showTail &&
styled.css`
background-image: url(${caretUp});
`};
background-position: top 0 right .5rem;
background-repeat: no-repeat;
z-index: 9999;
visibility: hidden;
${({visible}) =>
visible &&
styled.css`
visibility: visible;
`}
`;
export const IconMenuContent = styled.default.div`
background-color: ${colors.gray100};
border: 1px solid ${colors.gray200};
width: 200px;
overflow: auto;
border-radius: ${spacing.xxSmall};
padding: ${spacing.small} 0;
z-index: 10;
`;
export const IconMenuDropDownItem = styled.default.div`
padding: ${spacing.small};
text-decoration: none;
display: flex;
align-items: center;
font-size: 16px;
cursor: pointer;
color: ${colors.black};
background-color: ${colors.white};
&:hover {
background-color: ${colors.gray400};
}
`;
export const DropdownIcon = styled.default.div<{disabled?: boolean}>`
display: flex;
justify-content: center;
cursor: pointer;
min-width: 1rem;
&.disabled {
pointer-events: none;
opacity: 0.5;
}
`;
export const IconMenuPointer = styled.default.div`
position: absolute;
background-color: ${colors.gray100};
transform: rotate(45deg);
`;

View File

@@ -0,0 +1,19 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export enum IconMenuPosition {
Left = 'left',
Right = 'right',
Top = 'top',
TopLeft = 'top-left',
TopRight = 'top-right',
Bottom = 'bottom',
BottomLeft = 'bottom-left',
BottomRight = 'bottom-right'
}
const defaultArrowWidth = 12;
const defaultArrowEdgeGap = 8;
export {defaultArrowWidth, defaultArrowEdgeGap};

View File

@@ -1,4 +1,16 @@
export * from './buttons';
export * from './channel-icon-menu';
export * from './error-renderer';
export * from './layout';
export * from './loaders';
export * from './modal';
export * from './new-tab-link';
export * from './pre-formatted-code';
export * from './tags';
export * from './table-screen-header';
export * from './table-with-pagination';
export * from './ui';
export * from './tooltip';
export * from './ProtectedRoute';
export * from './table';
export * from './typography';

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export * from './indicators';

View File

@@ -0,0 +1,11 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX} from 'react';
import {LoadingWheel as Loader} from 'components/loaders';
import {SingleStreamSymbol, OfflineSymbol, MultipleStreamSymbol, Indicator} from './style';
export const OfflineIndicator = (): JSX.Element => <Indicator><OfflineSymbol /></Indicator>;
export const SingleStreamIndicator = (): JSX.Element => <Indicator className="single-stream-indicator"><SingleStreamSymbol className="testId-singleStreamIndicator" /></Indicator>;
export const MultiStreamIndicator = (): JSX.Element => <Indicator className="multi-stream-indicator"><MultipleStreamSymbol className="testId-multiStreamIndicator" /></Indicator>;
export const LoadingIndicator = (): JSX.Element => <Indicator><Loader size="medium" /></Indicator>;

View File

@@ -0,0 +1,43 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {LoadingWheel as Loader} from 'components';
export const Indicator = styled.default.div`
display: flex;
align-items: center;
justify-content: center;
${Loader} {
flex: 0;
margin: 0;
& span {
margin: 0;
}
}
`;
export const IndicatorOutline = styled.default.div`
width: 20px;
height: 20px;
border-radius: 50%;
`;
export const OfflineSymbol = styled.default(IndicatorOutline)`
border: 3px solid #707070;
background-color: transparent;
`;
export const SingleStreamSymbol = styled.default(IndicatorOutline)`
background-color: #08BD0B;
`;
export const MultipleStreamSymbol = styled.default(SingleStreamSymbol)`
width: 1rem;
height: 1rem;
margin-left: -2px;
box-shadow: 9px 0 0 0 #08BD0B;
`;

View File

@@ -0,0 +1,41 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX} from 'react';
import {useSelector} from 'react-redux';
import {AppStore} from 'store';
import {DataRowType} from 'components/table';
import {SingleStreamIndicator, OfflineIndicator, MultiStreamIndicator, LoadingIndicator} from './indicators';
interface IPublishingStateIndicator {
row: DataRowType;
publishingStateKey: string;
idKey: string;
}
const PublishingStateIndicator = ({
row,
publishingStateKey,
idKey
}: IPublishingStateIndicator): JSX.Element => {
const id = row[idKey];
const publishingState = useSelector((state: AppStore) => publishingStateKey && state[publishingStateKey as keyof AppStore]?.publishingState);
const rowPublishingState = publishingState.find((record: Record<string, any>) => record[idKey] === id);
if (!rowPublishingState) {
return <LoadingIndicator />;
}
if (!rowPublishingState.isOnline) {
return <OfflineIndicator />;
}
if (rowPublishingState.multipleStreams) {
return <MultiStreamIndicator />;
}
return <SingleStreamIndicator />;
};
export default PublishingStateIndicator;

View File

@@ -0,0 +1 @@
export * from '../forms/label';

View File

@@ -0,0 +1,57 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
interface IColumn {
align?: string;
size?: number;
padding?: string;
}
const {footerHeight} = Theme;
export const AppContainer = styled.default.div`
margin: 3.5rem 0 ${footerHeight};
height: calc(100vh - 3.5rem - ${footerHeight});
overflow: auto;
display: flex;
overflow-x: hidden;
`;
export const Body = styled.default.div`
width: 100%;
margin: 4rem 0;
padding: 0 ${Theme.spacing.xlarge};
background: ${Theme.colors.gray900};
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
min-height: calc(100vh - 2rem);
overflow: auto;
max-height: calc(100vh - 2rem);
max-width: calc(100vw - 2rem);
`;
export const Row = styled.default.div`
display: flex;
`;
export const Column = styled.default.div<IColumn>`
flex: ${({size}): number => size || 1};
text-align: ${({align}): string => align || 'right'};
${({padding}) =>
padding &&
styled.css`
padding: ${padding};
`}
`;
export const Main = styled.default.div`
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
`;

View File

@@ -2,7 +2,7 @@
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
import Theme from 'theme';
interface LoadingWheelProps {
size?: 'small' | 'medium' | 'large';
@@ -15,11 +15,11 @@ const LoadingWheelContainer = styled.default.div<{
color: string;
}>`
display: inline-block;
width: ${({ size }) => size}px;
height: ${({ size }) => size}px;
border: 3px solid ${({ color }) => color}20;
width: ${({size}) => size}px;
height: ${({size}) => size}px;
border: 3px solid ${({color}) => color}20;
border-radius: 50%;
border-top-color: ${({ color }) => color};
border-top-color: ${({color}) => color};
animation: spin 1s ease-in-out infinite;
@keyframes spin {
@@ -29,26 +29,14 @@ const LoadingWheelContainer = styled.default.div<{
}
`;
export const LoadingWheel: React.FC<LoadingWheelProps> = ({
size = 'medium',
color = Theme.colors.white,
className
}) => {
export const LoadingWheel: React.FC<LoadingWheelProps> = ({size = 'medium', color = Theme.colors.white, className}) => {
const sizeMap = {
small: Theme.loaderSize.small,
medium: Theme.loaderSize.medium,
large: Theme.loaderSize.large
};
return (
<LoadingWheelContainer
size={sizeMap[size]}
color={color}
className={className}
role="status"
aria-label="Loading"
/>
);
return <LoadingWheelContainer size={sizeMap[size]} color={color} className={className} role="status" aria-label="Loading" />;
};
export default LoadingWheel;

View File

@@ -0,0 +1,5 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as Modal} from './modal';

View File

@@ -0,0 +1,40 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {LoadingWheel as Loader} from 'components';
import PreFormattedCode from 'components/pre-formatted-code';
import okImage from 'assets/images/icon/ok.svg';
import errorImage from 'assets/images/icon/error.svg';
import React from 'react';
import {DialogResponse, StatusCode, FormLoaderContainer} from './style';
interface IFormResponseComponent {
response: {
error: string | boolean | Error;
status: number | string;
data?: any; //eslint-disable-line
};
}
const FormResponse = (props: IFormResponseComponent): React.JSX.Element => {
const {response} = props;
return !response ? (
<FormLoaderContainer>
<Loader color="dark" size="medium" />
</FormLoaderContainer>
) : (
<DialogResponse error={response.error || ''}>
<h3 className="testId-responseModal">{response.error ? 'Error' : 'Success'}</h3>
<div className="response-icon">
<img src={response.error ? errorImage : okImage} alt="status icon" />
</div>
<StatusCode error={response.error}>Status: {response.status}</StatusCode>
{response.data && typeof response.data === 'object' && <PreFormattedCode data={response.data} />}
{response.error && typeof response.error === 'string' && <PreFormattedCode data={{error: response.error}} />}
</DialogResponse>
);
};
export default FormResponse;

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as FormResponse} from './form-response';

View File

@@ -0,0 +1,175 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
import {InputComponentWrapper} from 'components/forms/Input';
// import {AdvancedSelectContainer, ComponentWrapper} from 'components/ui/advanced-select/advanced-select';
// import InputWithTagsWrapper from 'components/ui/input-with-tags/input-with-tags';
// import TagContainer from 'components/ui/input-with-tags/input-with-tags';
// import TagWrapper from 'components/ui/input-with-tags/input-with-tags';
const {spacing, blackWithOpacity, typography, colors, primaryBorderRadius, primaryBorderColor} = Theme;
export const DialogContent = styled.default.div`
display: flex;
width: 400px;
margin: ${spacing.small};
`;
export const DialogForm = styled.default.div`
display: flex;
flex-direction: column;
width: 100%;
/* stylelint-disable */
& ${InputComponentWrapper} {
width: 100%;
max-width: 100%;
}
/* TagWrapper {
& > div {
width: 100%;
max-width: 100%;
}
} */
/* stylelint-enable */
h3 {
color: ${colors.gray700};
font-size: ${typography.fontSizeXl};
line-height: 24px;
font-weight: 500;
letter-spacing: 0.36px;
display: flex;
align-items: flex-start;
a {
font-size: ${typography.fontSizeS};
margin: 0 0 0 0.5rem;
}
}
> p {
color: ${blackWithOpacity};
font-size: ${typography.primaryFontSize};
margin-top: ${spacing.small};
line-height: 24px;
i {
font-weight: bold;
padding: 0 ${spacing.xsmall};
}
a {
color: ${colors.lightBlue};
text-decoration: underline;
}
}
strong {
p {
margin-top: 0;
margin-bottom: ${spacing.xSmall};
}
svg {
margin: 0 ${spacing.xxSmall};
color: ${colors.lightBlue};
}
}
select {
background: ${colors.transparent};
border: 1px solid ${primaryBorderColor} !important;
}
input {
padding: ${spacing.small};
margin-bottom: ${spacing.xSmall};
}
.button-group {
display: flex;
margin-top: ${spacing.small};
justify-content: center;
}
.error-text {
font-size: ${typography.fontSizeXS};
color: ${colors.lightRed};
}
.loading {
width: 100%;
position: absolute;
top: 0;
right: 0;
background-color: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
}
`;
export const Options = styled.default.div`
display: flex;
align-items: flex-end;
&>div {
margin: 0 1rem 0 0;
}
`;
export const DialogResponse = styled.default(DialogContent)<{error?: string | boolean | Error}>`
width: 100%;
margin: 0;
flex-direction: column;
align-items: center;
justify-content: center;
h3 {
color: ${colors.green};
font-size: ${typography.fontSizeXl};
line-height: 24px;
font-weight: 500;
letter-spacing: 0.36px;
${({error}) =>
error &&
styled.css`
color: ${colors.lightRed};
`}
}
.response-icon{
img {
width: 100px;
height: 100px;
margin: ${spacing.small} 0;
}
}
.json-renderer {
margin-top: ${spacing.small};
width: 100%;
height: auto;
height: 300px;
padding: ${spacing.small};
overflow: auto;
background-color: ${colors.gray200};
font-size: ${typography.fontSizeS};
}
`;
export const StatusCode = styled.default.div<{error?: string | boolean | Error}>`
display: flex;
justify-content: center;
width: 100%;
margin: ${spacing.xxSmall} 0;
padding: ${spacing.xsmall} 0;
color: ${colors.green};
border-radius: ${primaryBorderRadius};
border: 1px solid ${colors.green};
${({error}) =>
error &&
styled.css`
border-color: ${colors.lightRed};
color: ${colors.lightRed};
`}
`;
export const Error = styled.default.div`
font-size: ${typography.fontSizeXS};
color: ${colors.lightRed};
`;
export const FormLoaderContainer = styled.default.div`
height: 430px;
display: flex;
justify-content: center;
align-items: center;
`;

View File

@@ -0,0 +1,87 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {createPortal} from 'react-dom';
import {ConfirmButton} from 'components/buttons';
import {theme} from 'components/shared/theme';
import {ModalOverlay, ModalContainer, ModalButtonsContaier, CloseButton} from './style';
interface IModal {
children: React.JSX.Element;
close: () => void;
className?: string;
submitButton?: {
onClick: () => void;
label?: string;
className?: string;
disabled?: boolean;
textColor?: string;
backgroundColor?: string;
borderColor?: string;
};
cancelButton?: {
onClick?: () => void;
label?: string;
className?: string;
disabled?: boolean;
textColor?: string;
backgroundColor?: string;
borderColor?: string;
};
}
const Modal = (props: IModal): React.JSX.Element => {
const {children, className, close} = props;
const submitButton = {
onClick: props.submitButton?.onClick || null,
label: 'Submit',
disabled: false,
textColor: theme.colors.gray700,
backgroundColor: theme.colors.white,
borderColor: theme.colors.gray700,
...props.submitButton
};
const cancelButton = {
label: 'Cancel',
disabled: false,
textColor: theme.colors.white,
backgroundColor: theme.colors.gray700,
borderColor: theme.colors.gray700,
...props.cancelButton
};
const handleCancel = () => {
if (cancelButton?.onClick) {
cancelButton.onClick();
} else {
close();
}
};
const clickModalContainer = (e: React.MouseEvent) => {
e.stopPropagation();
};
return createPortal(
<ModalOverlay onClick={close}>
<ModalContainer className={className} onClick={clickModalContainer}>
<CloseButton onClick={close} />
{children}
<ModalButtonsContaier>
{submitButton.onClick && <ConfirmButton {...submitButton} onClick={submitButton.onClick}>{submitButton.label}</ConfirmButton>}
{!props.cancelButton ||
(!cancelButton.disabled && (
<ConfirmButton className="testId-cancel" {...cancelButton} onClick={handleCancel}>
{cancelButton.label}
</ConfirmButton>
))}
</ModalButtonsContaier>
</ModalContainer>
</ModalOverlay>,
document.body
);
};
export default Modal;

View File

@@ -0,0 +1,5 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as MultiStepModal} from './multi-step-modal';

View File

@@ -0,0 +1,66 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState} from 'react';
import {Modal} from 'components/modal';
interface IMultiStepModal {
isOpen: boolean;
closeModal: () => void;
steps: {
title: string;
component: React.JSX.Element;
saveButton?: {
onClick?: () => void;
text?: string;
disabled?: boolean;
className?: string;
};
cancel?: () => void;
cancelDisabled?: boolean;
}[];
}
const MultiStepModal = ({isOpen, closeModal, steps}: IMultiStepModal): React.JSX.Element => {
const [currentStep, setCurrentStep] = useState(0);
const isLastStep = steps.length - 1 === currentStep;
const saveButtonText = isLastStep ? 'Done' : 'Next';
const handleCloseModal = () => {
closeModal();
setCurrentStep(0);
};
const handleSave = () => {
if (steps[currentStep]?.saveButton?.onClick) {
steps[currentStep].saveButton.onClick();
}
if (isLastStep) {
handleCloseModal();
} else {
setCurrentStep(currentStep + 1);
}
};
if (isOpen) {
return (
<Modal
close={handleCloseModal}
submitButton={{
className: steps[currentStep]?.saveButton?.className,
disabled: steps[currentStep]?.saveButton?.disabled,
onClick: handleSave,
label: steps[currentStep]?.saveButton?.text || saveButtonText
}}
cancelButton={{disabled: steps[currentStep]?.cancelDisabled}}>
{steps[currentStep]?.component || null}
</Modal>
);
}
return null;
};
export default MultiStepModal;

View File

@@ -0,0 +1,80 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {theme, paddings} from 'components/shared/theme';
import {ConfirmButton} from 'components/buttons';
const {colors} = theme;
export const ModalOverlay = styled.default.div`
position: fixed;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: ${colors.halfTransparentBlack};
top: 0;
left: 0;
z-index: 9999;
`;
export const ModalContainer = styled.default.div`
width: 60%;
max-width: 800px;
border-radius: 4px;
padding: ${paddings.xlarge};
background-color: ${colors.white};
position: relative;
max-height: 90%;
overflow: auto;
&.full-width {
width: auto;
max-width: 100%;
overflow-x: hidden;
}
&.dark {
background-color: ${colors.gray1000}
}
`;
export const CloseButton = styled.default.span`
cursor: pointer;
height: 1rem;
width: 1rem;
color: ${colors.gray700};
position: absolute;
top: 0.5rem;
right: 0.5rem;
&:before,
&:after {
position: absolute;
left: 0.4rem;
content: ' ';
height: 1rem;
width: 0.2rem;
background-color: ${colors.gray700};
}
&:before {
transform: rotate(45deg);
}
&:after {
transform: rotate(-45deg);
}
`;
export const ModalButtonsContaier = styled.default.div`
display: flex;
justify-content: center;
align-items: center;
margin: 24px 0 0;
${ConfirmButton} {
margin: 0 0.5rem;
}
`;

View File

@@ -0,0 +1,26 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {IconDefinition} from '@fortawesome/fontawesome-svg-core';
interface ILink {
icon?: IconDefinition;
text?: string;
iconColor?: string;
link: string;
}
export const NewTabLink = (props: ILink & Partial<HTMLLinkElement>): React.JSX.Element => {
const {icon, className, text, link, iconColor = 'white'} = props;
return (
<a rel="noopener noreferrer" target="_blank" href={link} className={className}>
{icon && <FontAwesomeIcon icon={icon} style={{color: iconColor}} />}
{text}
</a>
);
};
export default NewTabLink;

View File

@@ -0,0 +1,5 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export * from './pagination';
export {default as Pagination} from './pagination';

View File

@@ -0,0 +1,87 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {Fragment} from 'react';
import {
PaginationWrapper,
ItemRange,
PaginationContainer,
PageButton
} from './style';
interface IPagination {
currentPageNumber: number;
numberOfItems: number;
itemsPerPage: number;
setCurrentPage: (page: number) => void;
itemText?: string;
}
export const Pagination = (props: IPagination): JSX.Element => {
const maxNumberOfButtonsToShow = 3;
const LowerBoundLimit = 2;
const higherBoundLimit = 1;
const {currentPageNumber, numberOfItems, itemsPerPage, setCurrentPage, itemText} = props;
const totalNumberOfPages = Math.ceil(numberOfItems / itemsPerPage);
const setPage = (page: number): void => {
setCurrentPage(page);
};
const minimumItemBoundPerPage = ((currentPageNumber - 1) * itemsPerPage) + 1;
const maximumItemBoundPerPage = (currentPageNumber) * itemsPerPage;
const generateButtons = (bounds = 1): JSX.Element[] => {
const buttonToShow = maxNumberOfButtonsToShow > totalNumberOfPages ? totalNumberOfPages : maxNumberOfButtonsToShow;
const buttons = [];
let count: number;
if (currentPageNumber <= bounds) {
count = 1;
} else if ((currentPageNumber + bounds) > totalNumberOfPages) {
count = currentPageNumber - (buttonToShow - (totalNumberOfPages - currentPageNumber + 1));
} else {
count = currentPageNumber - bounds;
}
for (let y = 0; y < buttonToShow; y++) {
buttons.push(
<PageButton
key={`page-button-${y}`}
onClick={() => setPage(count + y)}
active={currentPageNumber === count + y}>
{count + y}
</PageButton>
);
}
return buttons;
};
return (
<PaginationContainer className="pagination-container">
{numberOfItems ? (
<PaginationWrapper>
{(currentPageNumber >= LowerBoundLimit) && (
<Fragment>
{currentPageNumber > 2 && totalNumberOfPages !== 3 && <PageButton onClick={() => setPage(1)}>1</PageButton>}
{(currentPageNumber > LowerBoundLimit) && currentPageNumber !== 3 && <p>...</p>}
</Fragment>
)}
{generateButtons()}
{(currentPageNumber <= totalNumberOfPages - higherBoundLimit) && (
<Fragment>
{(currentPageNumber < totalNumberOfPages - higherBoundLimit) && currentPageNumber + 2 !== totalNumberOfPages && <p>...</p>}
{currentPageNumber + 1 !== totalNumberOfPages && totalNumberOfPages !== 3 && <PageButton onClick={() => setPage(totalNumberOfPages)}>
{totalNumberOfPages}
</PageButton>}
</Fragment>
)}
</PaginationWrapper>
) : null}
<ItemRange>
{numberOfItems > 0 ? minimumItemBoundPerPage : 0} - {maximumItemBoundPerPage > numberOfItems ? numberOfItems : maximumItemBoundPerPage} of {numberOfItems} {itemText ? itemText : `channels`}
</ItemRange>
</PaginationContainer>
);
};
export default Pagination;

View File

@@ -0,0 +1,45 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {theme, paddings} from 'components/shared/theme';
const {
colors,
fontSizeS,
spacing,
primaryThemeColor
} = theme;
export const PaginationContainer = styled.default.div`
display: flex;
width: 100%;
align-items: center;
flex-wrap: wrap;
margin: ${spacing.small} 0;
`;
export const PaginationWrapper = styled.default.div`
display: flex;
flex-wrap: wrap;
`;
export const ItemRange = styled.default.div`
display: flex;
justify-content: flex-end;
margin-left: auto;
font-size: ${fontSizeS};
color: ${colors.lightBlue};
`;
export const PageButton = styled.default.button <{active?: boolean}>`
margin: 0 ${paddings.xsmall} ${paddings.xsmall} 0;
font-size: ${fontSizeS};
border: 1px solid ${primaryThemeColor};
border-radius: 4px;
height: 28px;
width: 36px;
cursor: pointer;
background-color: ${({active}) => active ? primaryThemeColor : 'transparent'};
color: ${({active}) => active ? colors.white : primaryThemeColor};
`;

View File

@@ -0,0 +1,5 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default} from './pre-formatted-code';

View File

@@ -0,0 +1,58 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {Fragment, useState} from 'react';
import {faCopy, faCheck} from '@fortawesome/free-solid-svg-icons';
import IconButton from 'components/buttons/icon-button';
import {CodeContainer} from './styles';
interface IPreFormattedCode {
data: Record<string, any> | Array<any>; // eslint-disable-line
prefixCharacter?: string;
color?: string;
showCopyIcon?: boolean;
}
const iconChangeTimeout = 2000;
const PreFormattedCode = ({data, prefixCharacter, color, showCopyIcon = true}: IPreFormattedCode): React.JSX.Element => {
const [copied, setCopied] = useState(false);
const json = JSON.stringify(data, null, 2);
const lines = json.split('\n');
const text = lines.map(line => line.replace(/^< /, '')).join('\n');
const copyJsonToClipboard = (text: string): void => {
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), iconChangeTimeout);
};
const handleCopy = event => {
const originalString = event.target.textContent;
const modifiedString = originalString.replace(/[<>]/g, '');
event.clipboardData.setData('text/plain', modifiedString);
event.preventDefault();
};
const handleCopyIconClick = () => copyJsonToClipboard(text);
return (
<CodeContainer color={color}>
<pre>
<code onCopy={handleCopy}>
{lines.map((line, index) => (
<Fragment key={index}>
{prefixCharacter} {line} <br />
{index === lines.length - 1 && prefixCharacter}
</Fragment>
))}
</code>
</pre>
{showCopyIcon && <IconButton onClick={handleCopyIconClick} tooltipText="Copy" icon={copied ? faCheck : faCopy} />}
</CodeContainer>
);
};
export default PreFormattedCode;

View File

@@ -0,0 +1,34 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
const {colors} = Theme;
export const CodeContainer = styled.default.div<{color?: string}>`
background-color: ${colors.gray200};
padding: 1rem;
margin: 1rem 0 0;
display: flex;
color: ${({color}) => color || colors.black};
position: relative;
width: 100%;
&>span {
position: absolute;
right: 0.5rem;
top: 0.5rem;
}
pre {
width: 100%;
white-space: pre-wrap;
max-height: 40vh;
overflow: auto;
}
code {
word-wrap: break-word;
}
`;

View File

@@ -0,0 +1,6 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as RestrictedTextWithLabel} from './restricted-text-with-label';
export {default as RestrictedText} from './restricted-text';
export * from './restricted-text';

View File

@@ -0,0 +1,34 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX} from 'react';
import {RestrictedRowLabel, RestrictedRowText, RestrictedRowWrapper} from './style';
import {RestrictedText} from '.';
interface IRestrictedTextWithLabel {
label: string;
text: string;
isLink?: boolean;
linkClassName?: string;
labelIcon?: JSX.Element;
}
const RestrictedTextWithLabel = ({
label,
text,
labelIcon,
isLink = false,
linkClassName = ''
}: IRestrictedTextWithLabel): JSX.Element => {
return (
<RestrictedRowWrapper>
<RestrictedRowLabel>{label} {labelIcon}</RestrictedRowLabel>
<RestrictedRowText>
<RestrictedText text={text} isLink={isLink} linkClassName={linkClassName} />
</RestrictedRowText>
</RestrictedRowWrapper>
);
};
export default RestrictedTextWithLabel;

View File

@@ -0,0 +1,115 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX, useEffect, useRef, useState} from 'react';
import {faEye, faEyeSlash} from '@fortawesome/free-regular-svg-icons';
import {Link} from 'components/ui';
import IconButton from 'components/buttons/icon-button';
import {CopyIconButton} from 'components/buttons/copy-icon-button';
import NewTabLink from 'components/new-tab-link';
import {RestrictedDiv, MeasuringBlock, TruncatedBlock} from './style';
export interface IRestrictedText {
text: string;
hasViewOption?: boolean;
hasCopyOption?: boolean;
isLink?: boolean;
linkValue?: string;
linkClassName?: string;
index?: number;
fullWidth?: boolean;
}
const iconButtonsWidth = 48;
export const RestrictedText = ({
text,
hasViewOption = true,
hasCopyOption = true,
isLink = false,
linkValue,
linkClassName = '',
fullWidth = true
}: IRestrictedText): JSX.Element => {
const restrictedDivRef = useRef(null);
const measuringRef = useRef(null);
const [showValue, setShowValue] = useState(false);
const [showEyeIcon, setShowEyeIcon] = useState(hasViewOption);
useEffect(() => {
const handleResize = () => {
handleShowEyeIcon();
};
window.addEventListener('resize', handleResize);
handleShowEyeIcon();
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
const handleShowEyeIcon = () => {
if (!restrictedDivRef.current || !measuringRef.current) {
return;
}
const containerWidth = restrictedDivRef.current.clientWidth - iconButtonsWidth;
const fullTextWidth = measuringRef.current.getBoundingClientRect()?.width;
setShowEyeIcon(fullTextWidth > containerWidth);
};
const handleShowValueChange = () => setShowValue(!showValue);
const CurrentTextView = (): JSX.Element => {
if (isLink && !linkValue) {
return (
<NewTabLink
link={text}
className={linkClassName}
text={text}
/>
);
}
if (isLink && linkValue) {
return (
<Link
to={linkValue}
className={linkClassName}
>
{text}
</Link>
);
}
return <>{text}</>;
};
return (
<RestrictedDiv ref={restrictedDivRef} className={`testId-truncatedDetails ${fullWidth && 'full-width'}`}>
<MeasuringBlock ref={measuringRef}>{text}</MeasuringBlock>
<TruncatedBlock className={showValue ? '' : 'truncated'}>
<CurrentTextView />
</TruncatedBlock>
<div>
{showEyeIcon && (
<IconButton
onClick={handleShowValueChange}
tooltipText={showValue ? 'Hide' : 'Show'}
icon={showValue ? faEyeSlash : faEye}
className={`${isLink ? 'testId-permalink' : ''} testId-viewDetails`}
/>
)}
{hasCopyOption && (
<CopyIconButton text={text} displayText={false} className="testId-copyDetails" />
)}
</div>
</RestrictedDiv>
);
};
export default RestrictedText;

View File

@@ -0,0 +1,96 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
const {
colors,
typography,
spacing,
} = Theme;
export const RestrictedDiv = styled.default.div`
display: flex;
align-items: center;
justify-content: start;
word-wrap: break-word;
&.full-width {
width: 100%;
}
& div {
display: flex;
align-items: center;
justify-content: center;
align-content: center;
& span {
color: ${Theme.primaryThemeColor};
display: none;
cursor: pointer;
outline: none;
}
.icon-button {
width: 1.5rem;
height: 1.5rem;
}
}
&:hover {
& span {
display: block;
}
}
`;
export const TruncatedBlock = styled.default.p`
overflow: hidden;
padding: ${spacing.small} 0;
text-overflow: ellipsis;
&.truncated {
white-space: nowrap;
}
`;
export const MeasuringBlock = styled.default.p`
position: fixed;
visibility: hidden;
opacity: 0;
white-space: nowrap;
`;
export const RestrictedRowWrapper = styled.default.div`
display: flex;
`;
export const RestrictedRowLabel = styled.default.div`
width: 135px;
display: flex;
align-self: center;
color: ${colors.gray300};
font-size: ${typography.fontSizeS};
padding: ${spacing.small};
a {
margin: 0 0.25rem;
}
span {
margin: 0 2px;
}
`;
export const RestrictedRowText = styled.default.div`
color: ${colors.gray300};
font-size: ${typography.fontSizeS};
border-bottom: 1px solid ${colors.gray700};
padding: ${spacing.small};
width: calc(100% - 135px);
a {
color: ${colors.lightBlue};
overflow-wrap: anywhere;
text-decoration: none;
font-size: ${typography.fontSizeS};
}
`;

View File

@@ -0,0 +1,2 @@
export {default, theme, Theme} from '../../theme';
export * from '../../theme';

View File

@@ -12,9 +12,9 @@ export const truncateWord = (word = '', length = 30): string => {
return word;
};
export const isEqual = (a: any, b: any): boolean => { // eslint-disable-line
if (typeof(a) === typeof(b)) {
if (typeof(a) === 'object') {
export const isEqual = (a: unknown, b: unknown): boolean => {
if (typeof a === typeof b) {
if (typeof a === 'object') {
return JSON.stringify(a) === JSON.stringify(b);
}
@@ -39,8 +39,8 @@ export const mergeSimilarCSVFiles = (formerCSV: string, latterCSV: string): stri
return formerCSV;
};
export const chunk = (array: any[], size: number = 1) => { // eslint-disable-line
const arrayChunks = [];
export const chunk = <T>(array: T[], size: number = 1): T[][] => {
const arrayChunks: T[][] = [];
for (let i = 0; i < array.length; i += size) {
const arrayChunk = array.slice(i, i + size);
@@ -66,10 +66,7 @@ export const getRangeByInterval = (start: Date, end: Date, intervalAmount: Durat
export const getBrowserLimits = (): IBrowserLimits => browserLimits[PlatformDetectionService.browserName.toLowerCase()];
export const getMaxByPropertyName = (
array: Record<string, number | string | boolean>[],
propertyName: string
): number => {
export const getMaxByPropertyName = (array: Record<string, number | string | boolean>[], propertyName: string): number => {
let length = array.length;
let max = -Infinity;

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export {default as TableScreenHeader} from './table-screen-header';

View File

@@ -0,0 +1,37 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
const {colors} = Theme;
export const ScreenHeader = styled.default.div`
display: flex;
justify-content: space-between;
align-items: baseline;
flex-wrap: wrap;
width: 100%;
margin: 0 0 .5rem;
`;
export const ScreenHeaderControls = styled.default.div`
display: flex;
align-items: center;
`;
export const HeaderControlWrapper = styled.default.div`
margin-left: 12px;
`;
export const HeaderTitle = styled.default.div`
display: flex;
align-items: baseline;
h2 {
color: ${colors.white};
margin: 0 .5rem 0 0;
}
p {
color: ${colors.gray200};
}
`;

View File

@@ -0,0 +1,48 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {JSX} from 'react';
import {
ITableWithLoadMoreHeader,
ITableWithPaginationHeader,
TableHeaderKey
} from 'interfaces/tableProps';
import {ScreenHeader, ScreenHeaderControls, HeaderControlWrapper, HeaderTitle} from './style';
type ScreenHeaderProps = ITableWithLoadMoreHeader | ITableWithPaginationHeader;
export interface ITableScreenHeader {
title: string;
subtitle?: string;
screenHeader: ScreenHeaderProps;
renderControl: (screenHeader: ScreenHeaderProps, key: TableHeaderKey) => JSX.Element | null;
}
export const TableScreenHeader = ({
title,
subtitle = '',
screenHeader,
renderControl
}: ITableScreenHeader): JSX.Element => {
return (
<ScreenHeader className="table-header">
<HeaderTitle>
<h2>{title}</h2>
{subtitle && <p>{subtitle}</p>}
</HeaderTitle>
<ScreenHeaderControls>
{Object.keys(screenHeader).map(key => {
const headerControl = screenHeader[key].render
? screenHeader[key].render(key)
: renderControl(screenHeader, key as TableHeaderKey);
return headerControl ? (
<HeaderControlWrapper key={key}>{headerControl}</HeaderControlWrapper>
) : null;
})}
</ScreenHeaderControls>
</ScreenHeader>
);
};
export default TableScreenHeader;

View File

@@ -0,0 +1,6 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export * from 'components/table';
export {default as TableWithPagination} from './table-with-pagination';
export {default as Pagination} from '../pagination/pagination';

View File

@@ -0,0 +1,205 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {useEffect, useState} from 'react';
import {
DataRowType,
Table,
TableHeaderKey,
ITable,
ITableWithPaginationHeader,
ITableSort
} from 'components/table';
import {isEqual} from 'utility/validators';
import SearchInput from 'components/forms/SearchInput';
import {compare} from 'utility/sort';
import {TableScreenHeader} from 'components/table-screen-header/table-screen-header';
import {AddButton} from 'components/buttons/icon-buttons';
import {Pagination} from 'components/pagination/pagination' ;
import {Select} from 'components/ui/select';
import {useSort, useSearch} from 'utility/custom-hooks';
interface ITableWithPagination extends ITable {
screenHeader: ITableWithPaginationHeader;
paginationItemText?: string;
getCurrentDisplayList?: (data: Record<string, string | number | null>[]) => void;
}
const TableWithPagination = ({
title = '',
screenHeader,
columns,
data,
sortColumn,
sortDirection,
style,
paginationItemText,
errorMessage,
getCurrentDisplayList,
changeSortProps,
searchValue: propsSearchValue = '',
changeSearch
}: ITableWithPagination): JSX.Element => {
const [currentPageNumber, setCurrentPageNumber] = useState<number>(1);
const [currentData, setCurrentData] = useState<DataRowType[]>([]);
const [filteredData, setFilteredData] = useState<DataRowType[]>(data || []);
const [total, setTotal] = useState<number>(data ? data.length : 0);
const [rowsCount, setRowsCount] = useState(10);
const [sortData, setSortData] = useSort({
sortColumn,
sortDirection
});
const [searchValue, setSearchValue] = useSearch(propsSearchValue);
const amendMarginsInElementsHeight = (selector: string, action: 'add' | 'remove') => {
const element = document.querySelector(selector);
let elementHeight = element?.clientHeight || 0;
if (!element) {
return;
}
if (action === 'add') {
elementHeight += parseInt(window?.getComputedStyle(element).getPropertyValue('margin-top'));
elementHeight += parseInt(window?.getComputedStyle(element).getPropertyValue('margin-bottom'));
} else {
elementHeight -= parseInt(window?.getComputedStyle(element).getPropertyValue('margin-top'));
elementHeight -= parseInt(window?.getComputedStyle(element).getPropertyValue('margin-bottom'));
}
return elementHeight;
};
const calculateRowsCount = () => {
const tableContainerHeight = amendMarginsInElementsHeight('.table-container', 'remove') || 0;
const paginationHeight = amendMarginsInElementsHeight('.pagination-container', 'add') || 0;
const tableHeaderHeight = amendMarginsInElementsHeight('.table-header', 'add') || 0;
const tableRow = document.querySelector('.table-row') || {clientHeight: 50};
const rowHeight = tableRow?.clientHeight || 50;
const newRowsCount = Math.round((tableContainerHeight - paginationHeight - tableHeaderHeight) / rowHeight);
setRowsCount(newRowsCount || rowsCount);
};
useEffect(() => {
let pxRatioBeforeZoom = window.devicePixelRatio;
let windowHeightBeforeResize = window.innerHeight;
const trackResize = e => {
const pxRatioAfterZoom = e.devicePixelRatio;
const windowHeightAfterResize = e.target.innerHeight;
if (pxRatioAfterZoom !== pxRatioBeforeZoom || windowHeightAfterResize !== windowHeightBeforeResize) {
pxRatioBeforeZoom = pxRatioAfterZoom;
windowHeightBeforeResize = windowHeightAfterResize;
calculateRowsCount();
}
};
calculateRowsCount();
window.addEventListener('resize', trackResize);
return () => {
window.removeEventListener('resize', trackResize);
};
}, []);
useEffect(() => {
let newData = Array.isArray(data) ? [...data] : [];
if (searchValue && Array.isArray(data)) {
newData = data.filter(prop => {
return Object.keys(columns).some(key => {
return String(prop[key]).toLowerCase().includes(searchValue.toLowerCase());
});
});
}
if (!isEqual(newData, filteredData)) {
setFilteredData(newData);
}
if (!isEqual(total, newData.length)) {
setTotal(newData.length);
}
}, [data, searchValue, rowsCount, columns]);
useEffect(() => {
const start = (currentPageNumber - 1) * rowsCount;
const sortedData = sortData
? filteredData.sort((a, b) => compare(a, b, sortData.sortDirection, sortData.sortColumn))
: filteredData;
const newCurrentData = sortedData.slice(start, start + rowsCount);
if (!isEqual(newCurrentData, currentData)) {
setCurrentData(newCurrentData);
if (getCurrentDisplayList) {
getCurrentDisplayList(newCurrentData);
}
}
}, [filteredData, currentPageNumber, rowsCount, sortData]);
const search = (val: string) => {
if (val !== searchValue) {
if (changeSearch) {
changeSearch({searchValue: val});
} else {
setSearchValue(val);
}
setCurrentPageNumber(1);
}
};
const sort = (data: ITableSort) => {
if (changeSortProps) {
changeSortProps(data);
} else {
setSortData(data);
}
};
const renderControl = (screenHeader: ITableWithPaginationHeader, key: TableHeaderKey) => {
switch (key) {
case TableHeaderKey.Search:
return <SearchInput search={search} defaultValue={searchValue} />;
case TableHeaderKey.AddRow:
return <AddButton onClick={screenHeader[key]?.openAddRowModal} className="testId-hashAddButton" />;
case TableHeaderKey.SelectType:
return <Select {...screenHeader[key]} />;
default:
return null;
}
};
return (
<>
<TableScreenHeader
title={title}
screenHeader={screenHeader}
renderControl={renderControl}
/>
<Table
columns={columns}
data={currentData}
sortColumn={sortColumn}
sortDirection={sortDirection}
style={style}
sort={sort}
errorMessage={errorMessage}
/>
<Pagination
currentPageNumber={currentPageNumber}
setCurrentPage={setCurrentPageNumber}
numberOfItems={total}
itemsPerPage={rowsCount}
itemText={paginationItemText}
/>
</>
);
};
export default TableWithPagination;

View File

@@ -0,0 +1,8 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export * from 'interfaces/tableProps';
export {default as Table} from './table';
export * from './table-cells';
export * from './props';
export * from './style';

View File

@@ -0,0 +1,74 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {CSSProperties} from 'react';
import {DirectionType, ITableSearch, ITableSort} from 'interfaces/tableProps';
import {ITableCellDropdown} from '.';
export enum CellType {
Text = 'text',
Link = 'link',
Date = 'date',
DateTime = 'datetime',
DropDown = 'dropdown',
Component = 'component'
}
export type DataValueType = string | number | null | undefined;
export type DataRowType = Record<string, DataValueType>;
interface ITableCellText {
propName: string;
hasShow?: boolean;
hasCopy?: boolean;
isSortable?: boolean;
direction?: DirectionType;
sortable?: boolean;
mutate?: (value: DataValueType | boolean) => string | number;
}
export interface ITableColumn {
title: string;
type?: CellType;
textCell?: ITableCellText;
renderCell?: (row?: DataRowType) => React.JSX.Element;
dropdownCell?: Omit<ITableCellDropdown, 'row'>;
thStyle?: CSSProperties;
tdStyle?: CSSProperties;
hasBorder?: boolean;
sortAction?: (key: string) => void;
hideColumnAt?: number;
isHidden?: boolean;
width?: number;
path?: string;
}
export type ColumnsType = Record<string, ITableColumn>;
export interface ITableRow {
columns: ColumnsType;
row: DataRowType;
}
export interface ITable {
title?: string;
columns: ColumnsType;
className?: string;
data?: DataRowType[];
tableName?: string;
addRow?: (row?: DataRowType) => void;
searchProps?: string[];
sortColumn?: string;
sortDirection?: DirectionType;
style?: CSSProperties;
tableHeader?: Element;
tableBottom?: Element;
sort?: (data: ITableSort) => void;
errorMessage?: null | string;
isFetching?: boolean;
hasMore?: boolean;
searchValue?: string;
changeSearch?: (val: ITableSearch) => void;
changeSortProps?: (data: ITableSort) => void;
}

View File

@@ -0,0 +1,75 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
const {colors, typography, primaryBackground} = Theme;
export const Table = styled.default.table`
width: 100%;
max-height: calc(100vh - 2rem);
max-width: calc(100vw - 2rem);
border-collapse: collapse;
margin: 0;
table-layout: fixed;
background-color: ${Theme.blackWithOpacity};
`;
export const Thead = styled.default.thead`
color: ${colors.white};
& tr {
vertical-align: middle;
border: none;
& th {
top: -1px;
background-color: ${primaryBackground};
padding: ${Theme.spacing.small} 0;
z-index: 10;
&:last-child {
border: none;
}
}
}
`;
export const TH = styled.default.th<{active?: boolean; border?: boolean; width?: number}>`
color: ${({active}) => (active ? colors.white : colors.gray500)};
font-size: ${typography.fontSizeS};
cursor: pointer;
border: 1px solid transparent;
border-right-color: ${colors.gray700};
& span {
margin-left: .4rem;
}
`;
export const Tbody = styled.default.tbody`
tr:nth-child(odd) {
background: ${colors.gray800};
}
& tr {
border-color: transparent transparent ${colors.black} transparent;
height: 3rem;
& td {
color: ${colors.white};
padding: ${Theme.spacing.small};
word-wrap: break-word;
font-size: ${typography.fontSizeS};
position: relative;
text-align: center;
& > div,
& > p {
text-align: center;
justify-content: center;
}
& a {
color: ${colors.lightBlue};
text-decoration: none;
}
}
}
`;

View File

@@ -0,0 +1,18 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import TableRow from './table-row';
import {Tbody} from './style';
import {ColumnsType} from './props';
interface ITableBody {
columns: ColumnsType;
data: Record<string, string | number | null>[];
}
export const TableBody = ({columns, data}: ITableBody): React.JSX.Element => (
<Tbody>{data.length ? data.map((row, idx) => <TableRow key={`tableRow-${idx}-${Date.now()}`} columns={columns} row={row} />) : null}</Tbody>
);
export default TableBody;

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export * from './table-cell-dropdown';

View File

@@ -0,0 +1,29 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {DataRowType} from '../props';
export interface ITableCellDropdown {
row: DataRowType;
title?: string;
icon?: React.JSX.Element;
Component: (props: any) => React.JSX.Element; //eslint-disable-line
keys: string[];
action?: (key: string) => void;
componentProps?: Record<string, unknown>;
}
export const TableCellDropdown = ({title = '', Component, keys, action, componentProps, row}: ITableCellDropdown): React.JSX.Element => {
const data = {} as Record<string, unknown>;
keys.forEach(value => {
data[value] = row[value];
});
if (data.showDropdown !== undefined) {
return data.showDropdown ? <Component title={title} data={data} action={action} {...componentProps} /> : null;
}
return <Component title={title} data={data} action={action} {...componentProps} />;
};

View File

@@ -0,0 +1,66 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faCaretDown, faCaretUp} from '@fortawesome/free-solid-svg-icons';
import {DirectionType} from 'interfaces/tableProps';
import {TH} from './style';
import {ITableColumn, CellType} from './props';
interface ITableHeaderCell {
column: Partial<ITableColumn>;
sortHeaderColumn: string | null;
sortAction?: (key: string) => void;
}
export const TableHeaderCell = ({
column: {type, title, hasBorder = true, textCell, isHidden, width, thStyle},
sortHeaderColumn,
sortAction
}: ITableHeaderCell): React.JSX.Element | null => {
switch (type) {
case CellType.DropDown:
case CellType.Component: {
return (
<TH
border={hasBorder.toString()}
style={{
width,
maxWidth: width,
minWidth: width,
...thStyle
}}>
{title}
</TH>
);
}
case CellType.Date:
case CellType.DateTime:
case CellType.Link:
case CellType.Text:
default: {
const {propName, isSortable = true, direction} = textCell;
const handleOnClick = () => {
if (sortAction && isSortable) {
sortAction(propName);
}
};
const isActive = isSortable && sortAction && sortHeaderColumn && sortHeaderColumn === propName;
return isHidden ? null : (
<TH active={isActive} border={hasBorder.toString()} key={propName} onClick={handleOnClick} width={width} style={thStyle}>
{title}
{isActive && (
<span>
<FontAwesomeIcon icon={direction === DirectionType.Asc ? faCaretDown : faCaretUp} />
</span>
)}
</TH>
);
}
}
};

View File

@@ -0,0 +1,30 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {Thead} from './style';
import {TableHeaderCell} from './table-header-cell';
import {ColumnsType} from './props';
export interface ITableHeader {
columns: ColumnsType;
sortHeaderColumn: string | null;
sortAction: (key: string) => void;
}
export const TableHeader = ({columns, sortHeaderColumn, sortAction}: ITableHeader): React.JSX.Element => {
const renderHeader = (): React.JSX.Element[] =>
Object.keys(columns).map(
(key: string, index: number): React.JSX.Element => (
<TableHeaderCell key={`table-header-cell-${index}`} column={columns[key]} sortHeaderColumn={sortHeaderColumn} sortAction={sortAction} />
)
);
return (
<Thead>
<tr>{renderHeader()}</tr>
</Thead>
);
};
export default TableHeader;

View File

@@ -0,0 +1,91 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import moment from 'moment';
import {getDateFromNow} from 'utility/date';
import {DateComponent} from 'components/date-render-component';
import {RestrictedText} from 'components/restricted-text';
import {TableCellDropdown} from './table-cells';
import {CellType, ITableRow} from './props';
export const TableRow = ({columns, row}: ITableRow): React.JSX.Element | null => {
if (!row) {
return null;
}
return (
<tr className="table-row">
{Object.keys(columns).map((key, idx) => {
const {isHidden, renderCell, dropdownCell, textCell, type, path = '', tdStyle, width} = columns[key];
if (isHidden) {
return null;
}
if (renderCell) {
return (
<td key={`tableData${idx}`} style={tdStyle}>
{renderCell(row)}
</td>
);
} else if (dropdownCell) {
return (
<td
key={`tableData${idx}`}
style={{
width,
maxWidth: width,
minWidth: width,
...tdStyle
}}>
<TableCellDropdown row={row} {...dropdownCell} />
</td>
);
} else if (textCell) {
const {propName} = textCell;
const value = row[propName] || '';
if (type === CellType.Date) {
return (
<td key={`tableData${idx}`} style={tdStyle}>
{getDateFromNow(value)}
</td>
);
} else if (type === CellType.DateTime) {
return (
<td key={`tableData${idx}`} style={tdStyle}>
<DateComponent date={moment.utc(value)} />
</td>
);
} else if (type === CellType.Link) {
let link = path || '';
if (row.extraPath) {
link += `${path ? '/' : ''}${row.extraPath}`;
}
return (
<td key={`tableData${idx}`} style={tdStyle}>
<div>
<RestrictedText isLink linkValue={link} linkClassName="testId-tableLink" text={`${value}`} />
</div>
</td>
);
}
return (
<td key={`tableData${idx}`} style={tdStyle}>
<RestrictedText index={idx} text={`${value}`} />
</td>
);
}
return <td key={`tableData${idx}`} />;
})}
</tr>
);
};
export default TableRow;

View File

@@ -0,0 +1,107 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useEffect, useLayoutEffect, useState} from 'react';
import {DirectionType} from 'interfaces/tableProps';
import {compare} from 'utility/sort';
import {Error} from 'components/error-renderer/style';
import {Table as TableContainer} from './style';
import TableHeader from './table-header';
import TableBody from './table-body';
import {ITable, DataRowType, ColumnsType} from './props';
const defaultHideColumnWidth = 100;
const TableComponent = ({columns, data, sortColumn, sortDirection, sort, errorMessage}: ITable): React.JSX.Element => {
const getHeadersBasedOnWidth = (columns: ColumnsType) => {
const newHeaders: ColumnsType = {};
Object.keys(columns).forEach(key => {
const hideColumnAt = columns[key]?.hideColumnAt || defaultHideColumnWidth;
const isHidden: boolean = columns[key]?.isHidden || window.innerWidth <= hideColumnAt;
newHeaders[key] = {
...columns[key],
isHidden
};
});
return newHeaders;
};
const [sortHeaderColumn, setSortHeaderColumn] = useState<string | null>(sortColumn || null);
const [headers, setHeaders] = useState<ColumnsType>(getHeadersBasedOnWidth(columns));
const [modifiedData, setModifiedData] = useState<DataRowType[]>(data);
useEffect(() => {
if (sortColumn && sortDirection) {
const newHeaders: ColumnsType = {...headers};
if (headers[sortColumn]?.textCell) {
newHeaders[sortColumn] = {
...newHeaders[sortColumn],
textCell: {
...newHeaders[sortColumn].textCell,
direction: sortDirection,
propName: newHeaders[sortColumn].textCell?.propName || sortColumn
}
};
}
setHeaders(newHeaders);
}
}, [sortColumn, sortDirection]);
useEffect(() => {
setModifiedData(data);
}, [data]);
useEffect(() => {
setHeaders(columns);
}, [columns]);
useLayoutEffect(() => {
const updateComponentBasedOnWidth = () => {
setHeaders(getHeadersBasedOnWidth(columns));
};
window.addEventListener('resize', updateComponentBasedOnWidth);
return () => window.removeEventListener('resize', updateComponentBasedOnWidth);
});
const sortAction = (propName: string) => {
if (headers[propName]) {
const newHeaders = {...headers};
const currentDirection = newHeaders[propName].textCell.direction;
const newDirection = currentDirection === DirectionType.Asc ? DirectionType.Desc : DirectionType.Asc;
newHeaders[propName].textCell.direction = newDirection;
if (sort) {
sort({
sortColumn: propName,
sortDirection: newDirection
});
} else {
const newData = modifiedData.sort((a, b) => compare(a, b, newDirection, propName));
setModifiedData(newData);
}
setHeaders(newHeaders);
setSortHeaderColumn(propName);
}
};
return !errorMessage ? (
<TableContainer className="testId-table">
<TableHeader columns={headers} sortHeaderColumn={sortHeaderColumn} sortAction={sortAction} />
<TableBody columns={headers} data={modifiedData} />
</TableContainer>
) : (
<Error>{errorMessage || 'Error'}</Error>
);
};
export default TableComponent;

View File

@@ -0,0 +1,30 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import {FC, MouseEvent} from 'react';
import {TagContainer} from './style';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faTimes} from '@fortawesome/free-solid-svg-icons';
export interface ITag {
label: string;
onClose?: (event: MouseEvent<HTMLSpanElement>) => void | null;
handleClick?: () => void;
disabled?: boolean;
className?: string;
}
export const Tag: FC<ITag> = ({className, label, onClose = null, handleClick = () => null, disabled = false}: ITag) => {
const onKeyPress = (): void => null;
return (
<TagContainer onClick={handleClick} disabled={disabled} className={className}>
<p>{label}</p>
{onClose && (
<span role="button" tabIndex={-1} onKeyPress={onKeyPress} onClick={onClose}>
<FontAwesomeIcon icon={faTimes} />
</span>
)}
</TagContainer>
);
};

View File

@@ -0,0 +1,37 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {theme, paddings} from 'components/shared/theme';
const {colors, spacing, fontSizeXS} = theme;
export const TagContainer = styled.default.div<{size?: string; disabled?: boolean}>`
display: inline-flex;
align-items: center;
border-radius: 1rem;
font-weight: 500;
margin: ${spacing.xxSmall};
color: ${colors.white};
background-color: ${colors.gray700};
height: 24px;
padding: 0 ${paddings.small};
font-size: ${fontSizeXS};
${({disabled}) =>
disabled &&
styled.css`
opacity: 0.3;
pointer-events: none;
`}
p {
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
margin: 0;
}
span{
margin-top: 2px;
margin-left: ${spacing.xSmall};
}
`;

View File

@@ -0,0 +1,43 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState} from 'react';
import {TooltipContainer, TooltipBubble} from './style';
import {Position} from './types';
export {Position};
interface ITooltip {
message: string;
position: Position;
children: React.JSX.Element | React.JSX.Element[];
width?: number;
}
export const Tooltip = (props: ITooltip): React.JSX.Element => {
const {message, position, children, width} = props;
const [displayTooltip, setDisplayTooltip] = useState(false);
const showTooltip = () => {
setDisplayTooltip(true);
};
const hideTooltip = () => {
setDisplayTooltip(false);
};
return (
<TooltipContainer onBlur={hideTooltip} onMouseOut={hideTooltip}>
{displayTooltip && (
<TooltipBubble className={`tooltip-${position}`} width={width}>
<div className="tooltip-message">{message}</div>
</TooltipBubble>
)}
<span onFocus={showTooltip} onMouseOver={showTooltip}>
{children}
</span>
</TooltipContainer>
);
};
Tooltip.Position = Position;

View File

@@ -0,0 +1,89 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
const {colors, spacing, typography} = Theme;
export const TooltipContainer = styled.default.span`
position: relative;
`;
export const TooltipBubble = styled.default.div<{width?: number}>`
min-width: 120px;
max-width: 600px;
width: ${({width}) => width}px;
word-wrap: break-word;
position: absolute;
z-index: 999;
&::after {
content: '';
position: absolute;
}
&.tooltip-top {
bottom: 100%;
left: 50%;
padding-bottom: ${spacing.small};
transform: translateX(-50%);
&::after {
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-top: 9px solid rgba(0,0,0, .7);
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
}
&.tooltip-bottom {
top: 100%;
left: 50%;
padding-top: ${spacing.small};
transform: translateX(-50%);
&::after {
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-bottom: 9px solid rgba(0,0,0, .7);
top: 0;
left: 50%;
transform: translateX(-50%);
}
}
&.tooltip-left {
top: 50%;
right: 100%;
padding-right: ${spacing.small};
transform: translateY(-50%);
&::after {
border-left: 9px solid rgba(0,0,0, .7);
border-top: 9px solid transparent;
border-bottom: 9px solid transparent;
top: 50%;
right: 0;
transform: translateY(-50%);
}
}
&.tooltip-right {
top: 50%;
left: 100%;
padding-left: ${spacing.small};
transform: translateY(-50%);
&::after {
border-right: 9px solid rgba(0,0,0, .7);
border-top: 9px solid transparent;
border-bottom: 9px solid transparent;
top: 50%;
left: 0;
transform: translateY(-50%);
}
}
.tooltip-message {
background: rgba(0,0,0, .7);
border-radius: 3px;
color: ${colors.white};
font-size: ${typography.fontSizeS};
line-height: 1.4;
padding: ${spacing.small};
text-align: center;
}
`;

View File

@@ -0,0 +1,10 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export enum Position {
Top = 'top',
Bottom = 'bottom',
Left = 'left',
Right = 'right'
}

View File

@@ -2,8 +2,7 @@
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import Theme from 'theme';
import Theme from 'theme';
export const H1 = styled.default.h1`
font-family: ${Theme.typography.primaryFont};

View File

@@ -0,0 +1,202 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React, {useState, useEffect, useRef, KeyboardEvent, ChangeEvent, ReactElement} from 'react';
import {Tag, ITag} from 'components/tags';
import {isEqual} from 'components/shared/utils';
import {Label} from 'components/forms/label';
import {AdvancedSelectContainer, ComponentWrapper, InputContainer, SelectInput, TagOptions} from './style';
export interface IAdvancedSelectItem {
value: string;
type: string[];
dependency?: string[];
set?: string[];
}
interface IKeyboardEventWithTarget extends KeyboardEvent<HTMLInputElement> {
target: HTMLInputElement;
}
const advancedSelectHeight = 250;
interface IAdvancedSelect {
selectedItems: IAdvancedSelectItem[];
setSelectedItems: (items: IAdvancedSelectItem[]) => void;
data: IAdvancedSelectItem[];
label?: string;
labelColor?: string;
labelIcon?: React.JSX.Element;
labelClassName?: string;
labelHtmlFor?: string;
width?: number | string;
className?: string;
allowMultiple?: boolean;
}
export const AdvancedSelect = ({
allowMultiple = true,
selectedItems,
setSelectedItems,
data,
label,
labelColor,
labelIcon,
labelClassName,
labelHtmlFor,
width,
className
}: IAdvancedSelect): React.JSX.Element => {
const [inputValue, setInputValue] = useState<string>('');
const [selectedSets, setSelectedSets] = useState<string[]>([]);
const firstUpdate = useRef(true);
const ref = useRef(null);
const scrollToBottom = (): void => {
ref.current.scrollTop = ref.current.scrollHeight;
};
const getSelectedItemsSets = () => {
const selectedSets = [];
selectedItems.forEach((item: IAdvancedSelectItem) => {
if (item.set) {
item.set.forEach(set => {
selectedSets.push(set);
});
}
});
setSelectedSets(selectedSets);
};
useEffect(() => {
getSelectedItemsSets();
}, []);
useEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
const timeout = setTimeout(() => scrollToBottom(), 0);
getSelectedItemsSets();
return () => clearTimeout(timeout);
}, [selectedItems]);
const getTagsContainerHeight = () => {
return advancedSelectHeight - 32 - ref?.current?.clientHeight;
};
const getItemDependencies = (item: IAdvancedSelectItem): IAdvancedSelectItem[] => {
const allDependencies = [];
const getNestedDependencies = (dependencyItem: IAdvancedSelectItem): void => {
const itemAlreadySelected = selectedItems.some(selectedItem => selectedItem.value === dependencyItem.value);
const selectedItemsSet = new Set(selectedItems.map(item => item.value));
const dependenciesSet = new Set(allDependencies.map(item => item.value));
const oneOfTheDependenciesAlreadySelected = item.dependency?.some(dependency => selectedItemsSet.has(dependency) || dependenciesSet.has(dependency));
const itemIsANestedDependency = item.dependency?.includes(dependencyItem.value);
if ((itemIsANestedDependency && oneOfTheDependenciesAlreadySelected) || itemAlreadySelected) {
return;
}
allDependencies.push(dependencyItem);
if (!dependencyItem.dependency) {
return;
}
dependencyItem.dependency.forEach((dependencyName: string) => {
const originalDependencyItem = data.find((element: IAdvancedSelectItem) => isEqual(dependencyName, element.value));
getNestedDependencies(originalDependencyItem);
});
};
getNestedDependencies(item);
return allDependencies;
};
const selectItem = (item: IAdvancedSelectItem): void => {
const itemsToSelect = getItemDependencies(item);
setSelectedItems([...selectedItems, ...itemsToSelect]);
setInputValue('');
};
const filterTags = (datum: IAdvancedSelectItem) => {
return datum.value.toLowerCase().includes(inputValue.toLowerCase());
};
const generateAllItems = (): ReactElement<ITag>[] => {
const itemsToSelectFrom = data.filter((datum: IAdvancedSelectItem) => !selectedItems.includes(datum)).filter(filterTags);
return itemsToSelectFrom.map((datum: IAdvancedSelectItem) => (
<Tag
disabled={(!allowMultiple && !!selectedItems.length) || (datum.set && selectedSets.some(set => datum.set.includes(set)))}
key={datum.value}
label={datum.value}
handleClick={() => selectItem(datum)}
/>
));
};
const deselectItem = (item: IAdvancedSelectItem): void => {
const filteredItems = selectedItems.filter((datum: IAdvancedSelectItem) => {
if (datum.dependency) {
return !isEqual(datum, item) && !datum.dependency.includes(item.value);
}
return !isEqual(datum, item);
});
setSelectedItems(filteredItems);
};
const generateSelectedItems = (): ReactElement<ITag>[] => {
return selectedItems.map((item: IAdvancedSelectItem) => (
<Tag key={item.value} label={item.value} onClose={() => deselectItem(item)} className="testId-selectedItem" />
));
};
const handleInput = (event: ChangeEvent<HTMLInputElement>): void => {
setInputValue(event.target.value);
};
const onKeyDown = (event: IKeyboardEventWithTarget): void => {
if (event.key === 'Enter') {
const {value} = event.target;
selectItem({
value,
type: []
});
}
};
return (
<ComponentWrapper width={width}>
{!!label && <Label text={label} color={labelColor} icon={labelIcon} className={labelClassName} htmlFor={labelHtmlFor} />}
<AdvancedSelectContainer className={className}>
<InputContainer ref={ref}>
{generateSelectedItems()}
<SelectInput
disabled={!allowMultiple && !!selectedItems.length}
className="testId-advancedSelectInput"
onChange={handleInput}
onKeyDown={onKeyDown}
value={inputValue}
/>
</InputContainer>
<TagOptions height={getTagsContainerHeight() || 0}>{generateAllItems()}</TagOptions>
</AdvancedSelectContainer>
</ComponentWrapper>
);
};

View File

@@ -0,0 +1,4 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
export * from './advanced-select';

View File

@@ -0,0 +1,62 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import * as styled from 'styled-components';
import {theme, paddings} from 'components/shared/theme';
import {IInput} from '../input';
const {colors, primaryBorderRadius, spacing, formFieldWidth, formFieldMaxWidth} = theme;
export const ComponentWrapper = styled.default.div<IInput>`
position: relative;
width: ${({width}) => (width && isNaN(+width) ? width : (width || formFieldWidth) + 'px')};
max-width: ${formFieldMaxWidth}px;
display: flex;
flex-direction: column;
`;
export const AdvancedSelectContainer = styled.default.div`
color: ${colors.white};
width: ${theme.formFieldWidth}px;
height: ${theme.formFieldMaxHeight}px;
background-color: ${colors.gray500};
border-radius: ${primaryBorderRadius};
padding: ${paddings.small};
margin-top: 0;
`;
export const SelectInput = styled.default.input`
background-color: ${colors.transparent};
border: none;
line-height: 24px;
width: 100%;
color: ${colors.black};
padding: 0 ${paddings.xsmall};
`;
export const InputContainer = styled.default.div`
display: flex;
flex-wrap: wrap;
border: none;
border-radius: ${primaryBorderRadius};
background-color: ${colors.white};
padding: ${paddings.xsmall};
min-height: 40px;
overflow-y: auto;
input {
flex: 1;
}
`;
export const TagOptions = styled.default.div<{height: number}>`
height: 200px;
flex: 1;
overflow-y: auto;
margin-top: ${spacing.xSmall};
padding: ${paddings.xsmall};
${({height}) =>
height &&
styled.css`
height: ${height}px;
`}
`;

View File

@@ -0,0 +1,54 @@
/**
* Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
*/
import React from 'react';
import {ReactDatePickerProps} from 'react-datepicker';
import {Label} from 'components/label';
import {DatePickerContainer, DatePickerElement, HelperText} from './style';
interface IDatePicker extends Omit<ReactDatePickerProps, 'onChange'> {
label?: string;
labelColor?: string;
labelIcon?: React.JSX.Element;
labelHtmlFor?: string;
labelClassName?: string;
name: string;
onDateChange: (name: string, date: Date) => void;
error?: boolean;
helperText?: string;
helperTextClassName?: string;
width?: number | string;
}
const DatePicker = ({
label,
labelColor,
labelIcon,
labelHtmlFor,
labelClassName,
name,
onDateChange,
error,
helperText,
helperTextClassName,
width,
...rest
}: IDatePicker): React.JSX.Element => {
const handleOnChange = (date: Date) => onDateChange(name, date);
return (
<DatePickerContainer width={width}>
{!!label && <Label text={label} color={labelColor} icon={labelIcon} htmlFor={labelHtmlFor} className={labelClassName} />}
<DatePickerElement name={name} onChange={handleOnChange} {...rest} />
{!!helperText && (
<HelperText className={helperTextClassName} error={error}>
{helperText}
</HelperText>
)}
</DatePickerContainer>
);
};
export default DatePicker;

Some files were not shown because too many files have changed in this diff Show More