mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 15:27:46 +00:00
Merge pull request #294 from akhilmhdh/feat/new-settings-page
New Project Settings Page
This commit is contained in:
Generated
+181
-92
@@ -14,6 +14,7 @@
|
|||||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.19",
|
"@fortawesome/react-fontawesome": "^0.1.19",
|
||||||
"@headlessui/react": "^1.6.6",
|
"@headlessui/react": "^1.6.6",
|
||||||
|
"@hookform/resolvers": "^2.9.10",
|
||||||
"@radix-ui/react-accordion": "^1.1.0",
|
"@radix-ui/react-accordion": "^1.1.0",
|
||||||
"@radix-ui/react-alert-dialog": "^1.0.2",
|
"@radix-ui/react-alert-dialog": "^1.0.2",
|
||||||
"@radix-ui/react-checkbox": "^1.0.1",
|
"@radix-ui/react-checkbox": "^1.0.1",
|
||||||
@@ -51,6 +52,7 @@
|
|||||||
"react-code-input": "^3.10.1",
|
"react-code-input": "^3.10.1",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-grid-layout": "^1.3.4",
|
"react-grid-layout": "^1.3.4",
|
||||||
|
"react-hook-form": "^7.43.0",
|
||||||
"react-i18next": "^12.1.1",
|
"react-i18next": "^12.1.1",
|
||||||
"react-mailchimp-subscribe": "^2.1.3",
|
"react-mailchimp-subscribe": "^2.1.3",
|
||||||
"react-markdown": "^8.0.3",
|
"react-markdown": "^8.0.3",
|
||||||
@@ -64,7 +66,8 @@
|
|||||||
"tweetnacl-util": "^0.15.1",
|
"tweetnacl-util": "^0.15.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"uuidv4": "^6.2.13",
|
"uuidv4": "^6.2.13",
|
||||||
"yaml": "^2.2.0"
|
"yaml": "^2.2.0",
|
||||||
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/addon-essentials": "^7.0.0-beta.30",
|
"@storybook/addon-essentials": "^7.0.0-beta.30",
|
||||||
@@ -108,7 +111,6 @@
|
|||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||||
"integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
|
"integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.1.0",
|
"@jridgewell/gen-mapping": "^0.1.0",
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
"@jridgewell/trace-mapping": "^0.3.9"
|
||||||
@@ -121,7 +123,6 @@
|
|||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
||||||
"integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
|
"integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/set-array": "^1.0.0",
|
"@jridgewell/set-array": "^1.0.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
@@ -157,7 +158,6 @@
|
|||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
|
||||||
"integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
|
"integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -166,7 +166,6 @@
|
|||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
|
||||||
"integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
|
"integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.1.0",
|
"@ampproject/remapping": "^2.1.0",
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.18.6",
|
||||||
@@ -196,7 +195,6 @@
|
|||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
},
|
},
|
||||||
@@ -212,14 +210,12 @@
|
|||||||
"node_modules/@babel/core/node_modules/ms": {
|
"node_modules/@babel/core/node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core/node_modules/semver": {
|
"node_modules/@babel/core/node_modules/semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -265,7 +261,6 @@
|
|||||||
"version": "7.20.7",
|
"version": "7.20.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
|
||||||
"integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
|
"integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.20.5",
|
"@babel/compat-data": "^7.20.5",
|
||||||
"@babel/helper-validator-option": "^7.18.6",
|
"@babel/helper-validator-option": "^7.18.6",
|
||||||
@@ -284,7 +279,6 @@
|
|||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
@@ -293,7 +287,6 @@
|
|||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
@@ -301,8 +294,7 @@
|
|||||||
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
|
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||||
"version": "7.20.12",
|
"version": "7.20.12",
|
||||||
@@ -461,7 +453,6 @@
|
|||||||
"version": "7.20.11",
|
"version": "7.20.11",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
|
||||||
"integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
|
"integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-environment-visitor": "^7.18.9",
|
"@babel/helper-environment-visitor": "^7.18.9",
|
||||||
"@babel/helper-module-imports": "^7.18.6",
|
"@babel/helper-module-imports": "^7.18.6",
|
||||||
@@ -535,7 +526,6 @@
|
|||||||
"version": "7.20.2",
|
"version": "7.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
|
||||||
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
|
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.20.2"
|
"@babel/types": "^7.20.2"
|
||||||
},
|
},
|
||||||
@@ -586,7 +576,6 @@
|
|||||||
"version": "7.18.6",
|
"version": "7.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
|
||||||
"integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
|
"integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -610,7 +599,6 @@
|
|||||||
"version": "7.20.6",
|
"version": "7.20.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
|
||||||
"integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
|
"integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.18.10",
|
"@babel/template": "^7.18.10",
|
||||||
"@babel/traverse": "^7.20.5",
|
"@babel/traverse": "^7.20.5",
|
||||||
@@ -2897,6 +2885,14 @@
|
|||||||
"react-dom": "^16 || ^17 || ^18"
|
"react-dom": "^16 || ^17 || ^18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hookform/resolvers": {
|
||||||
|
"version": "2.9.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.9.10.tgz",
|
||||||
|
"integrity": "sha512-JIL1DgJIlH9yuxcNGtyhsWX/PgNltz+5Gr6+8SX9fhXc/hPbEIk6wPI82nhgvp3uUb6ZfAM5mqg/x7KR7NAb+A==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-hook-form": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.8",
|
"version": "0.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||||
@@ -7005,8 +7001,7 @@
|
|||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
"version": "4.14.191",
|
"version": "4.14.191",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/mdast": {
|
"node_modules/@types/mdast": {
|
||||||
"version": "3.0.10",
|
"version": "3.0.10",
|
||||||
@@ -8997,7 +8992,6 @@
|
|||||||
"version": "4.21.4",
|
"version": "4.21.4",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
|
||||||
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
|
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -10680,8 +10674,7 @@
|
|||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.284",
|
"version": "1.4.284",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
|
||||||
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
|
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
"version": "9.2.2",
|
"version": "9.2.2",
|
||||||
@@ -10977,7 +10970,6 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@@ -12818,7 +12810,6 @@
|
|||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -14991,7 +14982,6 @@
|
|||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"json5": "lib/cli.js"
|
"json5": "lib/cli.js"
|
||||||
},
|
},
|
||||||
@@ -15210,6 +15200,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"node_modules/lodash.castarray": {
|
"node_modules/lodash.castarray": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||||
@@ -16183,6 +16178,11 @@
|
|||||||
"object-assign": "^4.1.0"
|
"object-assign": "^4.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoclone": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
|
||||||
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
@@ -16464,8 +16464,7 @@
|
|||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
|
||||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
|
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/normalize-package-data": {
|
"node_modules/normalize-package-data": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
@@ -17625,6 +17624,11 @@
|
|||||||
"react-is": "^16.13.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/property-expr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||||
|
},
|
||||||
"node_modules/property-information": {
|
"node_modules/property-information": {
|
||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz",
|
||||||
@@ -18142,6 +18146,21 @@
|
|||||||
"react-dom": ">= 16.3.0"
|
"react-dom": ">= 16.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-hook-form": {
|
||||||
|
"version": "7.43.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.43.0.tgz",
|
||||||
|
"integrity": "sha512-/rVEz7T0gLdSFwPqutJ1kn2e0sQNyb9ci/hmwEYr2YG0KF/LSuRLvNrf9QWJM+gj88CjDpDW5Bh/1AD7B2+z9Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/react-hook-form"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-i18next": {
|
"node_modules/react-i18next": {
|
||||||
"version": "12.1.1",
|
"version": "12.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
|
||||||
@@ -21168,6 +21187,11 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/toposort": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||||
|
},
|
||||||
"node_modules/tr46": {
|
"node_modules/tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
@@ -21404,7 +21428,7 @@
|
|||||||
"version": "4.9.3",
|
"version": "4.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
||||||
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -21730,7 +21754,6 @@
|
|||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||||
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
||||||
"dev": true,
|
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@@ -22480,6 +22503,23 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/yup": {
|
||||||
|
"version": "0.32.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
|
||||||
|
"integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.15.4",
|
||||||
|
"@types/lodash": "^4.14.175",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"nanoclone": "^0.2.1",
|
||||||
|
"property-expr": "^2.0.4",
|
||||||
|
"toposort": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -22487,7 +22527,6 @@
|
|||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
|
||||||
"integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
|
"integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/gen-mapping": "^0.1.0",
|
"@jridgewell/gen-mapping": "^0.1.0",
|
||||||
"@jridgewell/trace-mapping": "^0.3.9"
|
"@jridgewell/trace-mapping": "^0.3.9"
|
||||||
@@ -22497,7 +22536,6 @@
|
|||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
||||||
"integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
|
"integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@jridgewell/set-array": "^1.0.0",
|
"@jridgewell/set-array": "^1.0.0",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||||
@@ -22525,14 +22563,12 @@
|
|||||||
"@babel/compat-data": {
|
"@babel/compat-data": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz",
|
||||||
"integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==",
|
"integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@babel/core": {
|
"@babel/core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.5.tgz",
|
||||||
"integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
|
"integrity": "sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ampproject/remapping": "^2.1.0",
|
"@ampproject/remapping": "^2.1.0",
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.18.6",
|
||||||
@@ -22555,7 +22591,6 @@
|
|||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
@@ -22563,14 +22598,12 @@
|
|||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -22606,7 +22639,6 @@
|
|||||||
"version": "7.20.7",
|
"version": "7.20.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
|
||||||
"integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
|
"integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/compat-data": "^7.20.5",
|
"@babel/compat-data": "^7.20.5",
|
||||||
"@babel/helper-validator-option": "^7.18.6",
|
"@babel/helper-validator-option": "^7.18.6",
|
||||||
@@ -22619,7 +22651,6 @@
|
|||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
@@ -22627,14 +22658,12 @@
|
|||||||
"semver": {
|
"semver": {
|
||||||
"version": "6.3.0",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -22753,7 +22782,6 @@
|
|||||||
"version": "7.20.11",
|
"version": "7.20.11",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
|
||||||
"integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
|
"integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/helper-environment-visitor": "^7.18.9",
|
"@babel/helper-environment-visitor": "^7.18.9",
|
||||||
"@babel/helper-module-imports": "^7.18.6",
|
"@babel/helper-module-imports": "^7.18.6",
|
||||||
@@ -22809,7 +22837,6 @@
|
|||||||
"version": "7.20.2",
|
"version": "7.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
|
||||||
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
|
"integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.20.2"
|
"@babel/types": "^7.20.2"
|
||||||
}
|
}
|
||||||
@@ -22844,8 +22871,7 @@
|
|||||||
"@babel/helper-validator-option": {
|
"@babel/helper-validator-option": {
|
||||||
"version": "7.18.6",
|
"version": "7.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
|
||||||
"integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
|
"integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@babel/helper-wrap-function": {
|
"@babel/helper-wrap-function": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
@@ -22863,7 +22889,6 @@
|
|||||||
"version": "7.20.6",
|
"version": "7.20.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz",
|
||||||
"integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
|
"integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/template": "^7.18.10",
|
"@babel/template": "^7.18.10",
|
||||||
"@babel/traverse": "^7.20.5",
|
"@babel/traverse": "^7.20.5",
|
||||||
@@ -24061,7 +24086,8 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz",
|
||||||
"integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==",
|
"integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@emotion/utils": {
|
"@emotion/utils": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -24366,7 +24392,14 @@
|
|||||||
"@headlessui/react": {
|
"@headlessui/react": {
|
||||||
"version": "1.6.6",
|
"version": "1.6.6",
|
||||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz",
|
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz",
|
||||||
"integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q=="
|
"integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"@hookform/resolvers": {
|
||||||
|
"version": "2.9.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.9.10.tgz",
|
||||||
|
"integrity": "sha512-JIL1DgJIlH9yuxcNGtyhsWX/PgNltz+5Gr6+8SX9fhXc/hPbEIk6wPI82nhgvp3uUb6ZfAM5mqg/x7KR7NAb+A==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"@humanwhocodes/config-array": {
|
"@humanwhocodes/config-array": {
|
||||||
"version": "0.11.8",
|
"version": "0.11.8",
|
||||||
@@ -27340,8 +27373,7 @@
|
|||||||
"@types/lodash": {
|
"@types/lodash": {
|
||||||
"version": "4.14.191",
|
"version": "4.14.191",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@types/mdast": {
|
"@types/mdast": {
|
||||||
"version": "3.0.10",
|
"version": "3.0.10",
|
||||||
@@ -28016,7 +28048,8 @@
|
|||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"acorn-node": {
|
"acorn-node": {
|
||||||
"version": "1.8.2",
|
"version": "1.8.2",
|
||||||
@@ -28150,7 +28183,8 @@
|
|||||||
"version": "3.5.2",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"ansi-align": {
|
"ansi-align": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
@@ -28444,7 +28478,8 @@
|
|||||||
"axios-auth-refresh": {
|
"axios-auth-refresh": {
|
||||||
"version": "3.3.3",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/axios-auth-refresh/-/axios-auth-refresh-3.3.3.tgz",
|
||||||
"integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg=="
|
"integrity": "sha512-2IbDhJ/h6ddNBBnnzn1VFK/qx17pE9aVqiafB8rx5LVHsJ1HtFpUGkbXY7PzTG+8P9HJWcyA3fNZl9BikSuilg==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"axobject-query": {
|
"axobject-query": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
@@ -28459,7 +28494,8 @@
|
|||||||
"version": "7.0.0-bridge.0",
|
"version": "7.0.0-bridge.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
|
||||||
"integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==",
|
"integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"babel-loader": {
|
"babel-loader": {
|
||||||
"version": "9.1.2",
|
"version": "9.1.2",
|
||||||
@@ -28838,7 +28874,6 @@
|
|||||||
"version": "4.21.4",
|
"version": "4.21.4",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
|
||||||
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
|
"integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"caniuse-lite": "^1.0.30001400",
|
"caniuse-lite": "^1.0.30001400",
|
||||||
"electron-to-chromium": "^1.4.251",
|
"electron-to-chromium": "^1.4.251",
|
||||||
@@ -29668,7 +29703,8 @@
|
|||||||
"cva": {
|
"cva": {
|
||||||
"version": "npm:[email protected]",
|
"version": "npm:[email protected]",
|
||||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.4.0.tgz",
|
||||||
"integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ=="
|
"integrity": "sha512-74enNN8O9ZNieycac/y8FxqgyzZhZbxmCitAtAeUrLPlxjSd5zA7LfpprmxEcOmQBnaGs5hYhiSGnJ0mqrtBLQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"damerau-levenshtein": {
|
"damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
@@ -30121,8 +30157,7 @@
|
|||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.4.284",
|
"version": "1.4.284",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
|
||||||
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
|
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "9.2.2",
|
"version": "9.2.2",
|
||||||
@@ -30368,8 +30403,7 @@
|
|||||||
"escalade": {
|
"escalade": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||||
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
|
"integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"escape-html": {
|
"escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
@@ -30632,7 +30666,8 @@
|
|||||||
"version": "8.6.0",
|
"version": "8.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz",
|
||||||
"integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==",
|
"integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"eslint-import-resolver-node": {
|
"eslint-import-resolver-node": {
|
||||||
"version": "0.3.7",
|
"version": "0.3.7",
|
||||||
@@ -30890,13 +30925,15 @@
|
|||||||
"version": "4.6.0",
|
"version": "4.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
|
||||||
"integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
|
"integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"eslint-plugin-simple-import-sort": {
|
"eslint-plugin-simple-import-sort": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-8.0.0.tgz",
|
||||||
"integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==",
|
"integrity": "sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"eslint-plugin-storybook": {
|
"eslint-plugin-storybook": {
|
||||||
"version": "0.6.10",
|
"version": "0.6.10",
|
||||||
@@ -31760,8 +31797,7 @@
|
|||||||
"gensync": {
|
"gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
|
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"get-caller-file": {
|
"get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
@@ -32325,7 +32361,8 @@
|
|||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
|
||||||
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
"integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"ieee754": {
|
"ieee754": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
@@ -33339,8 +33376,7 @@
|
|||||||
"json5": {
|
"json5": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"jsonfile": {
|
"jsonfile": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
@@ -33508,6 +33544,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
|
"lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"lodash.castarray": {
|
"lodash.castarray": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||||
@@ -33638,7 +33679,8 @@
|
|||||||
"version": "7.1.8",
|
"version": "7.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.8.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.8.tgz",
|
||||||
"integrity": "sha512-rRSa1aFmFnpDRFAhv5vIkWM4nPaoB9vnzIjuIKa1wGupfn2hdCNeaQHKpu4/muoc8n8J7yowjTP2oncA4/Rbgg==",
|
"integrity": "sha512-rRSa1aFmFnpDRFAhv5vIkWM4nPaoB9vnzIjuIKa1wGupfn2hdCNeaQHKpu4/muoc8n8J7yowjTP2oncA4/Rbgg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"md5.js": {
|
"md5.js": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@@ -34155,6 +34197,11 @@
|
|||||||
"object-assign": "^4.1.0"
|
"object-assign": "^4.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nanoclone": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
|
||||||
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||||
@@ -34344,8 +34391,7 @@
|
|||||||
"node-releases": {
|
"node-releases": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
|
||||||
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==",
|
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"normalize-package-data": {
|
"normalize-package-data": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
@@ -34935,7 +34981,8 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
|
||||||
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
|
"integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"postcss-modules-local-by-default": {
|
"postcss-modules-local-by-default": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
@@ -35044,7 +35091,8 @@
|
|||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.2.tgz",
|
||||||
"integrity": "sha512-5RjUbWRe305pUpc48MosoIp6uxZvZxrM6GyOgsbGLTce+ehePKNm7ziW2dLG2air9aXbGuXlHVSQQw4Lbosq3w==",
|
"integrity": "sha512-5RjUbWRe305pUpc48MosoIp6uxZvZxrM6GyOgsbGLTce+ehePKNm7ziW2dLG2air9aXbGuXlHVSQQw4Lbosq3w==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"pretty-error": {
|
"pretty-error": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
@@ -35132,6 +35180,11 @@
|
|||||||
"react-is": "^16.13.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"property-expr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||||
|
},
|
||||||
"property-information": {
|
"property-information": {
|
||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.1.1.tgz",
|
||||||
@@ -35437,7 +35490,8 @@
|
|||||||
"version": "5.6.1",
|
"version": "5.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
|
||||||
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==",
|
"integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-docgen": {
|
"react-docgen": {
|
||||||
"version": "5.4.3",
|
"version": "5.4.3",
|
||||||
@@ -35469,7 +35523,8 @@
|
|||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz",
|
||||||
"integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==",
|
"integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
@@ -35521,6 +35576,12 @@
|
|||||||
"react-resizable": "^3.0.4"
|
"react-resizable": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-hook-form": {
|
||||||
|
"version": "7.43.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.43.0.tgz",
|
||||||
|
"integrity": "sha512-/rVEz7T0gLdSFwPqutJ1kn2e0sQNyb9ci/hmwEYr2YG0KF/LSuRLvNrf9QWJM+gj88CjDpDW5Bh/1AD7B2+z9Q==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"react-i18next": {
|
"react-i18next": {
|
||||||
"version": "12.1.1",
|
"version": "12.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
|
||||||
@@ -35534,7 +35595,8 @@
|
|||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.1.tgz",
|
||||||
"integrity": "sha512-cxKSeFTf7jpSSVddm66sKdolG90qURAX3g1roTeaN6x0YEbtWc8JpmFN9+yIqLNH2uEkYerWLtJZIXRIFuBKrg==",
|
"integrity": "sha512-cxKSeFTf7jpSSVddm66sKdolG90qURAX3g1roTeaN6x0YEbtWc8JpmFN9+yIqLNH2uEkYerWLtJZIXRIFuBKrg==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
@@ -35649,7 +35711,8 @@
|
|||||||
"react-table": {
|
"react-table": {
|
||||||
"version": "7.8.0",
|
"version": "7.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz",
|
||||||
"integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA=="
|
"integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"read-cache": {
|
"read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -35805,7 +35868,8 @@
|
|||||||
"redux-thunk": {
|
"redux-thunk": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
|
||||||
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
|
"integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"regenerate": {
|
"regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
@@ -37258,7 +37322,8 @@
|
|||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz",
|
||||||
"integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
|
"integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"style-to-object": {
|
"style-to-object": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
@@ -37288,7 +37353,8 @@
|
|||||||
"styled-jsx": {
|
"styled-jsx": {
|
||||||
"version": "5.0.7",
|
"version": "5.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz",
|
||||||
"integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA=="
|
"integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"stylis": {
|
"stylis": {
|
||||||
"version": "4.0.13",
|
"version": "4.0.13",
|
||||||
@@ -37750,6 +37816,11 @@
|
|||||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"toposort": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||||
|
},
|
||||||
"tr46": {
|
"tr46": {
|
||||||
"version": "0.0.3",
|
"version": "0.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
@@ -37928,7 +37999,7 @@
|
|||||||
"version": "4.9.3",
|
"version": "4.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
|
||||||
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
"integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==",
|
||||||
"dev": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"uc.micro": {
|
"uc.micro": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
@@ -38164,7 +38235,6 @@
|
|||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||||
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"escalade": "^3.1.1",
|
"escalade": "^3.1.1",
|
||||||
"picocolors": "^1.0.0"
|
"picocolors": "^1.0.0"
|
||||||
@@ -38202,12 +38272,14 @@
|
|||||||
"use-isomorphic-layout-effect": {
|
"use-isomorphic-layout-effect": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
||||||
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
|
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"use-memo-one": {
|
"use-memo-one": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz",
|
||||||
"integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ=="
|
"integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"use-sidecar": {
|
"use-sidecar": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
@@ -38221,7 +38293,8 @@
|
|||||||
"use-sync-external-store": {
|
"use-sync-external-store": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
|
||||||
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA=="
|
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"util": {
|
"util": {
|
||||||
"version": "0.12.5",
|
"version": "0.12.5",
|
||||||
@@ -38412,7 +38485,8 @@
|
|||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
|
||||||
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
|
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"eslint-scope": {
|
"eslint-scope": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
@@ -38638,7 +38712,8 @@
|
|||||||
"version": "8.12.0",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
|
||||||
"integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
|
"integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
|
||||||
"dev": true
|
"dev": true,
|
||||||
|
"requires": {}
|
||||||
},
|
},
|
||||||
"xtend": {
|
"xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
@@ -38698,6 +38773,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"yup": {
|
||||||
|
"version": "0.32.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
|
||||||
|
"integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.15.4",
|
||||||
|
"@types/lodash": "^4.14.175",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"nanoclone": "^0.2.1",
|
||||||
|
"property-expr": "^2.0.4",
|
||||||
|
"toposort": "^2.0.2"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
"@fortawesome/free-solid-svg-icons": "^6.1.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.19",
|
"@fortawesome/react-fontawesome": "^0.1.19",
|
||||||
"@headlessui/react": "^1.6.6",
|
"@headlessui/react": "^1.6.6",
|
||||||
|
"@hookform/resolvers": "^2.9.10",
|
||||||
"@radix-ui/react-accordion": "^1.1.0",
|
"@radix-ui/react-accordion": "^1.1.0",
|
||||||
"@radix-ui/react-alert-dialog": "^1.0.2",
|
"@radix-ui/react-alert-dialog": "^1.0.2",
|
||||||
"@radix-ui/react-checkbox": "^1.0.1",
|
"@radix-ui/react-checkbox": "^1.0.1",
|
||||||
@@ -58,6 +59,7 @@
|
|||||||
"react-code-input": "^3.10.1",
|
"react-code-input": "^3.10.1",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-grid-layout": "^1.3.4",
|
"react-grid-layout": "^1.3.4",
|
||||||
|
"react-hook-form": "^7.43.0",
|
||||||
"react-i18next": "^12.1.1",
|
"react-i18next": "^12.1.1",
|
||||||
"react-mailchimp-subscribe": "^2.1.3",
|
"react-mailchimp-subscribe": "^2.1.3",
|
||||||
"react-markdown": "^8.0.3",
|
"react-markdown": "^8.0.3",
|
||||||
@@ -71,7 +73,8 @@
|
|||||||
"tweetnacl-util": "^0.15.1",
|
"tweetnacl-util": "^0.15.1",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"uuidv4": "^6.2.13",
|
"uuidv4": "^6.2.13",
|
||||||
"yaml": "^2.2.0"
|
"yaml": "^2.2.0",
|
||||||
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@storybook/addon-essentials": "^7.0.0-beta.30",
|
"@storybook/addon-essentials": "^7.0.0-beta.30",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"add-new": "Add New Token",
|
"add-new": "Add New Token",
|
||||||
"add-dialog": {
|
"add-dialog": {
|
||||||
"title": "Add a service token for {{target}}",
|
"title": "Add a service token for {{target}}",
|
||||||
"description": "Specify the name, environment, and expiry period. When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.",
|
"description": "When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.",
|
||||||
"name": "Service Token Name",
|
"name": "Service Token Name",
|
||||||
"add": "Add Service Token",
|
"add": "Add Service Token",
|
||||||
"copy-service-token": "Copy your service token",
|
"copy-service-token": "Copy your service token",
|
||||||
|
|||||||
@@ -187,10 +187,10 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
});
|
});
|
||||||
const userWorkspaces = orgUserProjects;
|
const userWorkspaces = orgUserProjects;
|
||||||
if (
|
if (
|
||||||
userWorkspaces.length === 0 &&
|
(userWorkspaces.length === 0 &&
|
||||||
router.asPath !== '/noprojects' &&
|
router.asPath !== '/noprojects' &&
|
||||||
!router.asPath.includes('home') &&
|
!router.asPath.includes('home') &&
|
||||||
!router.asPath.includes('settings') ||
|
!router.asPath.includes('settings')) ||
|
||||||
router.asPath === '/dashboard/undefined'
|
router.asPath === '/dashboard/undefined'
|
||||||
) {
|
) {
|
||||||
router.push('/noprojects');
|
router.push('/noprojects');
|
||||||
@@ -246,16 +246,15 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="fixed w-full md:block flex flex-col h-screen">
|
<div className="flex h-screen w-full flex-col overflow-x-hidden">
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.2.2/cdn.js" defer />
|
|
||||||
<NavBarDashboard />
|
<NavBarDashboard />
|
||||||
<div className="flex flex-col md:flex-row flex-1">
|
<div className="flex flex-grow flex-col overflow-y-hidden md:flex-row">
|
||||||
<aside className="bg-bunker-600 border-r border-mineshaft-500 w-full md:w-60 h-screen">
|
<aside className="w-full border-r border-mineshaft-500 bg-bunker-600 md:w-60">
|
||||||
<nav className="flex flex-col justify-between items-between h-full">
|
<nav className="items-between flex h-full flex-col justify-between">
|
||||||
{/* <div className="py-6"></div> */}
|
{/* <div className="py-6"></div> */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-center w-full mt-[4.5rem] mb-6 bg-bunker-600 h-20 flex-col items-center px-4">
|
<div className="mt-6 mb-6 flex h-20 w-full flex-col items-center justify-center bg-bunker-600 px-4">
|
||||||
<div className="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
<div className="ml-1 mb-1 self-start text-xs font-semibold tracking-wide text-gray-400">
|
||||||
{t('nav:menu.project')}
|
{t('nav:menu.project')}
|
||||||
</div>
|
</div>
|
||||||
{Object.keys(workspaceMapping).length > 0 ? (
|
{Object.keys(workspaceMapping).length > 0 ? (
|
||||||
@@ -279,29 +278,29 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
<ul>
|
<ul>
|
||||||
{Object.keys(workspaceMapping).length > 0 &&
|
{Object.keys(workspaceMapping).length > 0 &&
|
||||||
menuItems.map(({ href, title, emoji }) => (
|
menuItems.map(({ href, title, emoji }) => (
|
||||||
<li className="mt-0.5 mx-2" key={title}>
|
<li className="mx-2 mt-0.5" key={title}>
|
||||||
{router.asPath.split('/')[1] === href.split('/')[1] &&
|
{router.asPath.split('/')[1] === href.split('/')[1] &&
|
||||||
(['project', 'billing', 'org', 'personal'].includes(
|
(['project', 'billing', 'org', 'personal'].includes(
|
||||||
router.asPath.split('/')[2]
|
router.asPath.split('/')[2]
|
||||||
)
|
)
|
||||||
? router.asPath.split('/')[2] === href.split('/')[2]
|
? router.asPath.split('/')[2] === href.split('/')[2]
|
||||||
: true) ? (
|
: true) ? (
|
||||||
<div className="flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10">
|
<div className="relative flex cursor-pointer rounded bg-primary-50/10 px-0.5 py-2.5 text-sm text-white">
|
||||||
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1" />
|
<div className="absolute inset-0 top-0 my-1 ml-1 mr-1 w-1 rounded-xl bg-primary" />
|
||||||
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
|
<p className="ml-4 mr-2 flex w-6 items-center justify-center text-lg">
|
||||||
{emoji}
|
{emoji}
|
||||||
</p>
|
</p>
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
) : router.asPath === '/noprojects' ? (
|
) : router.asPath === '/noprojects' ? (
|
||||||
<div className="flex p-2.5 text-white text-sm rounded">
|
<div className="flex rounded p-2.5 text-sm text-white">
|
||||||
<p className="w-10 flex items-center justify-center text-lg">{emoji}</p>
|
<p className="flex w-10 items-center justify-center text-lg">{emoji}</p>
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Link href={href}>
|
<Link href={href}>
|
||||||
<div className="flex p-2.5 text-white text-sm rounded cursor-pointer hover:bg-primary-50/5">
|
<div className="flex cursor-pointer rounded p-2.5 text-sm text-white hover:bg-primary-50/5">
|
||||||
<p className="w-10 flex items-center justify-center text-lg">
|
<p className="flex w-10 items-center justify-center text-lg">
|
||||||
{emoji}
|
{emoji}
|
||||||
</p>
|
</p>
|
||||||
{title}
|
{title}
|
||||||
@@ -312,11 +311,11 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full mt-40 mb-4 px-2">
|
<div className="mt-40 mb-4 w-full px-2">
|
||||||
{router.asPath.split('/')[1] === 'home' ? (
|
{router.asPath.split('/')[1] === 'home' ? (
|
||||||
<div className="flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10">
|
<div className="relative flex cursor-pointer rounded bg-primary-50/10 px-0.5 py-2.5 text-sm text-white">
|
||||||
<div className="absolute top-0 my-1 ml-1 inset-0 bg-primary w-1 rounded-xl mr-1" />
|
<div className="absolute inset-0 top-0 my-1 ml-1 mr-1 w-1 rounded-xl bg-primary" />
|
||||||
<p className="w-6 ml-4 mr-2 flex items-center justify-center text-lg">
|
<p className="ml-4 mr-2 flex w-6 items-center justify-center text-lg">
|
||||||
<FontAwesomeIcon icon={faBookOpen} />
|
<FontAwesomeIcon icon={faBookOpen} />
|
||||||
</p>
|
</p>
|
||||||
Infisical Guide
|
Infisical Guide
|
||||||
@@ -336,8 +335,8 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Link href={`/home/${workspaceMapping[workspaceSelected as any]}`}>
|
<Link href={`/home/${workspaceMapping[workspaceSelected as any]}`}>
|
||||||
<div className="relative flex p-2.5 overflow-visible text-white h-10 text-sm rounded cursor-pointer bg-white/10 hover:bg-primary-50/[0.15] mt-max">
|
<div className="mt-max relative flex h-10 cursor-pointer overflow-visible rounded bg-white/10 p-2.5 text-sm text-white hover:bg-primary-50/[0.15]">
|
||||||
<p className="w-10 flex items-center justify-center text-lg">
|
<p className="flex w-10 items-center justify-center text-lg">
|
||||||
<FontAwesomeIcon icon={faBookOpen} />
|
<FontAwesomeIcon icon={faBookOpen} />
|
||||||
</p>
|
</p>
|
||||||
Infisical Guide
|
Infisical Guide
|
||||||
@@ -369,12 +368,12 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
error={error}
|
error={error}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
<main className="flex-1 bg-bunker-800">{children}</main>
|
<main className="flex-1 overflow-y-auto overflow-x-hidden bg-bunker-800">{children}</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="md:hidden bg-bunker-800 w-screen h-screen flex flex-col justify-center items-center">
|
<div className="flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 md:hidden">
|
||||||
<FontAwesomeIcon icon={faMobile} className="text-gray-300 text-7xl mb-8" />
|
<FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" />
|
||||||
<p className="text-gray-200 px-6 text-center text-lg max-w-sm">
|
<p className="max-w-sm px-6 text-center text-lg text-gray-200">
|
||||||
{` ${t('common:no-mobile')} `}
|
{` ${t('common:no-mobile')} `}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
const onEnvCreateCB = async (env: Env) => {
|
const onEnvCreateCB = async (env: Env) => {
|
||||||
try {
|
try {
|
||||||
await onCreateEnv(env);
|
await onCreateEnv(env);
|
||||||
@@ -71,14 +70,14 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row justify-between w-full">
|
<div className="flex w-full flex-row justify-between">
|
||||||
<div className="flex flex-col w-full">
|
<div className="flex w-full flex-col">
|
||||||
<p className="text-xl font-semibold mb-3">Project Environments</p>
|
<p className="mb-3 text-xl font-semibold">Project Environments</p>
|
||||||
<p className="text-base text-gray-400 mb-4">
|
<p className="mb-4 text-base text-gray-400">
|
||||||
Choose which environments will show up in your dashboard like development, staging,
|
Choose which environments will show up in your dashboard like development, staging,
|
||||||
production
|
production
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm mr-1 text-gray-500 self-start">
|
<p className="mr-1 self-start text-sm text-gray-500">
|
||||||
Note: the text in slugs shows how these environmant should be accessed in CLI.
|
Note: the text in slugs shows how these environmant should be accessed in CLI.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,10 +85,10 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
|
|||||||
<Button
|
<Button
|
||||||
text="Add New Env"
|
text="Add New Env"
|
||||||
onButtonPressed={() => {
|
onButtonPressed={() => {
|
||||||
if (plan !== plans.starter || host !== "https://app.infisical.com") {
|
if (plan !== plans.starter || host !== 'https://app.infisical.com') {
|
||||||
handlePopUpOpen('createUpdateEnv')
|
handlePopUpOpen('createUpdateEnv');
|
||||||
} else {
|
} else {
|
||||||
handlePopUpOpen('upgradePlan')
|
handlePopUpOpen('upgradePlan');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
color="mineshaft"
|
color="mineshaft"
|
||||||
@@ -98,32 +97,30 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="table-container w-full bg-bunker rounded-md mb-6 border border-mineshaft-700 relative mt-1">
|
<div className="table-container relative mb-6 mt-1 w-full rounded-md border border-mineshaft-700 bg-bunker">
|
||||||
<div className="absolute rounded-t-md w-full h-12 bg-white/5" />
|
<div className="absolute h-12 w-full rounded-t-md bg-white/5" />
|
||||||
<table className="w-full my-1">
|
<table className="my-1 w-full">
|
||||||
<thead className="text-bunker-300">
|
<thead className="text-bunker-300">
|
||||||
<tr>
|
<tr>
|
||||||
<th className="text-left pl-6 pt-2.5 pb-2">Name</th>
|
<th className="pl-6 pt-2.5 pb-2 text-left">Name</th>
|
||||||
<th className="text-left pl-6 pt-2.5 pb-2">Slug</th>
|
<th className="pl-6 pt-2.5 pb-2 text-left">Slug</th>
|
||||||
<th aria-label="buttons" />
|
<th aria-label="buttons" />
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{data?.length > 0 ? (
|
{data?.length > 0 ? (
|
||||||
data.map(({ name, slug }) => (
|
data.map(({ name, slug }) => (
|
||||||
<tr key={name} className="bg-bunker-800 hover:bg-bunker-800/5 duration-100">
|
<tr key={name} className="bg-bunker-800 duration-100 hover:bg-bunker-800/5">
|
||||||
<td className="pl-6 py-2 border-mineshaft-700 border-t text-gray-300">
|
<td className="border-t border-mineshaft-700 py-2 pl-6 text-gray-300">{name}</td>
|
||||||
{name}
|
<td className="border-t border-mineshaft-700 py-2 pl-6 text-gray-300">{slug}</td>
|
||||||
</td>
|
<td className="flex justify-end border-t border-mineshaft-700 py-2">
|
||||||
<td className="pl-6 py-2 border-mineshaft-700 border-t text-gray-300">{slug}</td>
|
<div className="mr-2 flex items-center duration-200 hover:opacity-100">
|
||||||
<td className="py-2 border-mineshaft-700 border-t flex justify-end">
|
|
||||||
<div className="hover:opacity-100 duration-200 flex items-center mr-2">
|
|
||||||
<Button
|
<Button
|
||||||
onButtonPressed={() => {
|
onButtonPressed={() => {
|
||||||
if (plan !== plans.starter || host !== "https://app.infisical.com") {
|
if (plan !== plans.starter || host !== 'https://app.infisical.com') {
|
||||||
handlePopUpOpen('createUpdateEnv', { name, slug })
|
handlePopUpOpen('createUpdateEnv', { name, slug });
|
||||||
} else {
|
} else {
|
||||||
handlePopUpOpen('upgradePlan')
|
handlePopUpOpen('upgradePlan');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
color="mineshaft"
|
color="mineshaft"
|
||||||
@@ -131,13 +128,13 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
|
|||||||
icon={faPencil}
|
icon={faPencil}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="opacity-50 hover:opacity-100 duration-200 flex items-center mr-6">
|
<div className="mr-6 flex items-center opacity-50 duration-200 hover:opacity-100">
|
||||||
<Button
|
<Button
|
||||||
onButtonPressed={() => {
|
onButtonPressed={() => {
|
||||||
if (plan !== plans.starter || host !== "https://app.infisical.com") {
|
if (plan !== plans.starter || host !== 'https://app.infisical.com') {
|
||||||
handlePopUpOpen('deleteEnv', { name, slug })
|
handlePopUpOpen('deleteEnv', { name, slug });
|
||||||
} else {
|
} else {
|
||||||
handlePopUpOpen('upgradePlan')
|
handlePopUpOpen('upgradePlan');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
color="red"
|
color="red"
|
||||||
@@ -150,8 +147,8 @@ const EnvironmentTable = ({ data = [], onCreateEnv, onDeleteEnv, onUpdateEnv }:
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={4} className="text-center pt-7 pb-4 text-bunker-400">
|
<td colSpan={4} className="pt-7 pb-4 text-center text-bunker-400">
|
||||||
No environmants found
|
No environments found
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ const SideBar = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute border-l border-mineshaft-500 bg-bunker h-full w-96 top-14 right-0 z-40 shadow-xl flex flex-col justify-between">
|
<div className="absolute border-l border-mineshaft-500 bg-bunker h-full w-96 right-0 z-40 shadow-xl flex flex-col justify-between">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center h-full">
|
<div className="flex items-center justify-center h-full">
|
||||||
<Image
|
<Image
|
||||||
@@ -171,7 +171,7 @@ const SideBar = ({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex justify-start max-w-sm mt-4 px-4 mt-full mb-[4.7rem]">
|
<div className="flex justify-start max-w-sm mt-4 px-4 mt-full mb-8">
|
||||||
<Button
|
<Button
|
||||||
text={String(t('common:save-changes'))}
|
text={String(t('common:save-changes'))}
|
||||||
onButtonPressed={savePush}
|
onButtonPressed={savePush}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export default function Navbar() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="absolute flex flex-row justify-between w-full bg-bunker text-white border-b border-mineshaft-500 z-50">
|
<div className="flex flex-row justify-between w-full bg-bunker text-white border-b border-mineshaft-500 z-50">
|
||||||
<div className="m-auto flex justify-start items-center mx-4">
|
<div className="m-auto flex justify-start items-center mx-4">
|
||||||
<div className="flex flex-row items-center">
|
<div className="flex flex-row items-center">
|
||||||
<div className="flex justify-center py-4">
|
<div className="flex justify-center py-4">
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { useRouter } from 'next/router';
|
|||||||
import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
|
import { faAngleRight } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
import { useWorkspace } from '@app/context';
|
||||||
import getOrganization from '@app/pages/api/organization/GetOrg';
|
import getOrganization from '@app/pages/api/organization/GetOrg';
|
||||||
import getProjectInfo from '@app/pages/api/workspace/getProjectInfo';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the component at the top of almost every page.
|
* This is the component at the top of almost every page.
|
||||||
@@ -23,9 +23,9 @@ export default function NavHeader({
|
|||||||
isProjectRelated?: boolean;
|
isProjectRelated?: boolean;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const [orgName, setOrgName] = useState('');
|
const [orgName, setOrgName] = useState('');
|
||||||
const [workspaceName, setWorkspaceName] = useState('');
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const projectId = String(router.query.id);
|
const projectId = String(router.query.id);
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -34,29 +34,24 @@ export default function NavHeader({
|
|||||||
orgId: orgId || ''
|
orgId: orgId || ''
|
||||||
});
|
});
|
||||||
setOrgName(org.name);
|
setOrgName(org.name);
|
||||||
|
|
||||||
const workspace = await getProjectInfo({
|
|
||||||
projectId
|
|
||||||
});
|
|
||||||
setWorkspaceName(workspace.name);
|
|
||||||
})();
|
})();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [projectId]);
|
}, [projectId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pt-20 ml-6 flex flex-row items-center">
|
<div className="ml-6 flex flex-row items-center pt-8">
|
||||||
<div className="bg-primary-900 h-6 w-6 rounded-md flex items-center justify-center text-mineshaft-100 mr-2">
|
<div className="mr-2 flex h-6 w-6 items-center justify-center rounded-md bg-primary-900 text-mineshaft-100">
|
||||||
{orgName?.charAt(0)}
|
{orgName?.charAt(0)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-primary text-sm font-semibold">{orgName}</div>
|
<div className="text-sm font-semibold text-primary">{orgName}</div>
|
||||||
{isProjectRelated && (
|
{isProjectRelated && (
|
||||||
<>
|
<>
|
||||||
<FontAwesomeIcon icon={faAngleRight} className="ml-3 text-sm text-gray-400 mr-3" />
|
<FontAwesomeIcon icon={faAngleRight} className="ml-3 mr-3 text-sm text-gray-400" />
|
||||||
<div className="font-semibold text-primary text-sm">{workspaceName}</div>
|
<div className="text-sm font-semibold text-primary">{currentWorkspace?.name}</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<FontAwesomeIcon icon={faAngleRight} className="ml-3 text-sm text-gray-400 mr-3" />
|
<FontAwesomeIcon icon={faAngleRight} className="ml-3 mr-3 text-sm text-gray-400" />
|
||||||
<div className="text-gray-400 text-sm">{pageName}</div>
|
<div className="text-sm text-gray-400">{pageName}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,15 @@ const buttonVariants = cva(
|
|||||||
'font-inter font-medium',
|
'font-inter font-medium',
|
||||||
'cursor-pointer',
|
'cursor-pointer',
|
||||||
'inline-flex items-center justify-center',
|
'inline-flex items-center justify-center',
|
||||||
'relative'
|
'relative',
|
||||||
|
'whitespace-nowrap'
|
||||||
],
|
],
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
colorSchema: {
|
colorSchema: {
|
||||||
primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'],
|
primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'],
|
||||||
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'],
|
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'],
|
||||||
danger: ['bg-red', 'text-white', 'border-red']
|
danger: ['bg-red', 'text-white', 'border-red hover:bg-opacity-90']
|
||||||
},
|
},
|
||||||
variant: {
|
variant: {
|
||||||
solid: '',
|
solid: '',
|
||||||
@@ -33,7 +34,7 @@ const buttonVariants = cva(
|
|||||||
plain: ''
|
plain: ''
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'bg-opacity-70 cursor-not-allowed',
|
true: 'bg-mineshaft opacity-40 cursor-not-allowed',
|
||||||
false: ''
|
false: ''
|
||||||
},
|
},
|
||||||
isFullWidth: {
|
isFullWidth: {
|
||||||
@@ -45,9 +46,9 @@ const buttonVariants = cva(
|
|||||||
false: ''
|
false: ''
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
xs: ['text-xs', 'py-1', 'px-2'],
|
xs: ['text-xs', 'py-1', 'px-1'],
|
||||||
sm: ['text-sm', 'py-2', 'px-4'],
|
sm: ['text-sm', 'py-2', 'px-2'],
|
||||||
md: ['text-md', 'py-2', 'px-6'],
|
md: ['text-md', 'py-2', 'px-4'],
|
||||||
lg: ['text-lg', 'py-2', 'px-8']
|
lg: ['text-lg', 'py-2', 'px-8']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -75,7 +76,7 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
colorSchema: 'secondary',
|
colorSchema: 'secondary',
|
||||||
variant: 'plain',
|
variant: 'plain',
|
||||||
className: 'text-mineshaft'
|
className: 'text-mineshaft-300'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'danger',
|
colorSchema: 'danger',
|
||||||
@@ -101,7 +102,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|||||||
children,
|
children,
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
className = '',
|
className = '',
|
||||||
size = 'md',
|
size = 'sm',
|
||||||
variant = 'solid',
|
variant = 'solid',
|
||||||
isFullWidth,
|
isFullWidth,
|
||||||
isRounded = true,
|
isRounded = true,
|
||||||
@@ -144,9 +145,10 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'transition-all shrink-0 cursor-pointer',
|
'shrink-0 cursor-pointer transition-all',
|
||||||
loadingToggleClass,
|
loadingToggleClass,
|
||||||
size === 'xs' ? 'mr-1' : 'mr-2'
|
leftIcon && 'ml-2',
|
||||||
|
size === 'xs' ? 'mr-1' : 'mr-3'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{leftIcon}
|
{leftIcon}
|
||||||
@@ -154,7 +156,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|||||||
<span className={twMerge('transition-all', loadingToggleClass)}>{children}</span>
|
<span className={twMerge('transition-all', loadingToggleClass)}>{children}</span>
|
||||||
<span
|
<span
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'transition-all shrink-0 cursor-pointer',
|
'shrink-0 cursor-pointer transition-all',
|
||||||
loadingToggleClass,
|
loadingToggleClass,
|
||||||
size === 'xs' ? 'ml-1' : 'ml-2'
|
size === 'xs' ? 'ml-1' : 'ml-2'
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export type CardTitleProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CardTitle = ({ children, className, subTitle }: CardTitleProps) => (
|
export const CardTitle = ({ children, className, subTitle }: CardTitleProps) => (
|
||||||
<div className={twMerge('p-6 pb-4 font-sans text-xl font-medium', className)}>
|
<div className={twMerge('px-6 py-4 font-sans text-xl font-medium', className)}>
|
||||||
{children}
|
{children}
|
||||||
{subTitle && <p className="py-1 text-sm font-normal text-gray-400">{subTitle}</p>}
|
{subTitle && <p className="py-1 text-sm font-normal text-gray-400">{subTitle}</p>}
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +29,7 @@ export type CardBodyProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CardBody = ({ children, className }: CardBodyProps) => (
|
export const CardBody = ({ children, className }: CardBodyProps) => (
|
||||||
<div className={twMerge('p-6 pt-0', className)}>{children}</div>
|
<div className={twMerge('px-6 pb-6 pt-0', className)}>{children}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export type CardProps = {
|
export type CardProps = {
|
||||||
@@ -47,7 +47,7 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'flex flex-col w-full font-inter text-gray-200 bg-mineshaft-700 shadow-md',
|
'flex w-full flex-col bg-mineshaft-800 font-inter text-gray-200 shadow-md',
|
||||||
isFullHeight && 'h-full',
|
isFullHeight && 'h-full',
|
||||||
isRounded && 'rounded-md',
|
isRounded && 'rounded-md',
|
||||||
isPlain && 'shadow-none',
|
isPlain && 'shadow-none',
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { useToggle } from '@app/hooks';
|
||||||
|
|
||||||
|
import { Button } from '../Button';
|
||||||
|
import { FormControl } from '../FormControl';
|
||||||
|
import { Input } from '../Input';
|
||||||
|
import { Modal, ModalContent } from '../Modal';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isOpen?: boolean;
|
||||||
|
onClose?: () => void;
|
||||||
|
onChange?: (isOpen: boolean) => void;
|
||||||
|
deleteKey: string;
|
||||||
|
title: string;
|
||||||
|
onDeleteApproved: () => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DeleteActionModal = ({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
onChange,
|
||||||
|
deleteKey,
|
||||||
|
onDeleteApproved,
|
||||||
|
title
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const [inputData, setInputData] = useState('');
|
||||||
|
const [isLoading, setIsLoading] = useToggle();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setInputData('');
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
const onDelete = async () => {
|
||||||
|
setIsLoading.on();
|
||||||
|
try {
|
||||||
|
await onDeleteApproved();
|
||||||
|
} catch {
|
||||||
|
setIsLoading.off();
|
||||||
|
} finally {
|
||||||
|
setIsLoading.off();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
onOpenChange={(isOpenState) => {
|
||||||
|
setInputData('');
|
||||||
|
if (onChange) onChange(isOpenState);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ModalContent
|
||||||
|
title={title}
|
||||||
|
subTitle="This action is irreversible!!!"
|
||||||
|
footerContent={
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
colorSchema="danger"
|
||||||
|
isDisabled={!(deleteKey === inputData) || isLoading}
|
||||||
|
onClick={onDelete}
|
||||||
|
isLoading={isLoading}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
<Button variant="plain" colorSchema="secondary" onClick={onClose}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
onClose={onClose}
|
||||||
|
>
|
||||||
|
<form>
|
||||||
|
<FormControl
|
||||||
|
label={
|
||||||
|
<div className="pb-2 text-sm">
|
||||||
|
Type <span className="font-bold">{deleteKey}</span> to delete the resource
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
className="mb-4"
|
||||||
|
>
|
||||||
|
<Input value={inputData} onChange={(e) => setInputData(e.target.value)} />
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { DeleteActionModal } from './DeleteActionModal';
|
||||||
@@ -11,7 +11,7 @@ export type FormLabelProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const FormLabel = ({ id, label, isRequired }: FormLabelProps) => (
|
export const FormLabel = ({ id, label, isRequired }: FormLabelProps) => (
|
||||||
<Label.Root className="text-mineshaft-300 text-sm font-medium block mb-1 ml-0.5" htmlFor={id}>
|
<Label.Root className="mb-1 ml-0.5 block text-sm font-medium text-mineshaft-300" htmlFor={id}>
|
||||||
{label}
|
{label}
|
||||||
{isRequired && <span className="ml-1 text-red">*</span>}
|
{isRequired && <span className="ml-1 text-red">*</span>}
|
||||||
</Label.Root>
|
</Label.Root>
|
||||||
@@ -25,7 +25,7 @@ export type FormHelperTextProps = {
|
|||||||
export const FormHelperText = ({ isError, text }: FormHelperTextProps) => (
|
export const FormHelperText = ({ isError, text }: FormHelperTextProps) => (
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'text-xs font-inter flex items-center opacity-90 text-mineshaft-300 mt-2',
|
'mt-2 flex items-center font-inter text-xs text-mineshaft-300 opacity-90',
|
||||||
isError && 'text-red-600'
|
isError && 'text-red-600'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -46,6 +46,7 @@ export type FormControlProps = {
|
|||||||
helperText?: ReactNode;
|
helperText?: ReactNode;
|
||||||
errorText?: ReactNode;
|
errorText?: ReactNode;
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FormControl = ({
|
export const FormControl = ({
|
||||||
@@ -55,10 +56,11 @@ export const FormControl = ({
|
|||||||
helperText,
|
helperText,
|
||||||
errorText,
|
errorText,
|
||||||
id,
|
id,
|
||||||
isError
|
isError,
|
||||||
|
className
|
||||||
}: FormControlProps): JSX.Element => {
|
}: FormControlProps): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className={twMerge('mb-4', className)}>
|
||||||
{typeof label === 'string' ? (
|
{typeof label === 'string' ? (
|
||||||
<FormLabel label={label} isRequired={isRequired} id={id} />
|
<FormLabel label={label} isRequired={isRequired} id={id} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const iconButtonVariants = cva(
|
|||||||
[
|
[
|
||||||
'button',
|
'button',
|
||||||
'transition-all',
|
'transition-all',
|
||||||
'font-inter font-medium',
|
'font-inter font-medium user-select-none',
|
||||||
'cursor-pointer',
|
'cursor-pointer',
|
||||||
'inline-flex items-center justify-center',
|
'inline-flex items-center justify-center',
|
||||||
'relative'
|
'relative'
|
||||||
@@ -22,9 +22,9 @@ const iconButtonVariants = cva(
|
|||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
colorSchema: {
|
colorSchema: {
|
||||||
primary: ['bg-primary', 'text-black', 'border-primary hover:bg-opacity-80'],
|
primary: ['bg-primary', 'text-black', 'border-primary hover:opacity-80'],
|
||||||
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-opacity-80'],
|
secondary: ['bg-mineshaft', 'text-gray-300', 'border-mineshaft hover:bg-bunker-400'],
|
||||||
danger: ['bg-red', 'text-white', 'border-red']
|
danger: ['bg-[#973939] hover:bg-red', 'text-white', 'border-red']
|
||||||
},
|
},
|
||||||
variant: {
|
variant: {
|
||||||
solid: '',
|
solid: '',
|
||||||
@@ -40,10 +40,10 @@ const iconButtonVariants = cva(
|
|||||||
false: ''
|
false: ''
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
xs: ['text-xs', 'py-1', 'px-2'],
|
xs: ['text-xs', 'py-2', 'px-2'],
|
||||||
sm: ['text-sm', 'py-2', 'px-3'],
|
sm: ['text-sm', 'py-3', 'px-3'],
|
||||||
md: ['text-md', 'py-3', 'px-4'],
|
md: ['text-md', 'py-4', 'px-4'],
|
||||||
lg: ['text-lg', 'py-3', 'px-6']
|
lg: ['text-lg', 'py-6', 'px-6']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
compoundVariants: [
|
compoundVariants: [
|
||||||
@@ -97,7 +97,7 @@ export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|||||||
ariaLabel,
|
ariaLabel,
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
className,
|
className,
|
||||||
size = 'md',
|
size = 'sm',
|
||||||
variant = 'solid',
|
variant = 'solid',
|
||||||
isRounded = true,
|
isRounded = true,
|
||||||
colorSchema = 'primary',
|
colorSchema = 'primary',
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ type Props = {
|
|||||||
isRequired?: boolean;
|
isRequired?: boolean;
|
||||||
leftIcon?: ReactNode;
|
leftIcon?: ReactNode;
|
||||||
rightIcon?: ReactNode;
|
rightIcon?: ReactNode;
|
||||||
|
isDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const inputVariants = cva(
|
const inputVariants = cva(
|
||||||
'input w-full py-2 text-gray-400 placeholder-gray-500 placeholder-opacity-50',
|
'input w-full py-2 text-gray-400 placeholder-gray-500 placeholder-opacity-50 outline-none focus:ring-2',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
@@ -46,7 +47,7 @@ const inputParentContainerVariants = cva('inline-flex font-inter items-center bo
|
|||||||
},
|
},
|
||||||
isError: {
|
isError: {
|
||||||
true: 'border-red',
|
true: 'border-red',
|
||||||
false: 'border-mineshaft-400'
|
false: 'border-mineshaft-500'
|
||||||
},
|
},
|
||||||
isFullWidth: {
|
isFullWidth: {
|
||||||
true: 'w-full',
|
true: 'w-full',
|
||||||
@@ -70,6 +71,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||||||
className,
|
className,
|
||||||
isRounded = true,
|
isRounded = true,
|
||||||
isFullWidth = true,
|
isFullWidth = true,
|
||||||
|
isDisabled,
|
||||||
isError = false,
|
isError = false,
|
||||||
isRequired,
|
isRequired,
|
||||||
leftIcon,
|
leftIcon,
|
||||||
@@ -87,9 +89,10 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||||||
{...props}
|
{...props}
|
||||||
required={isRequired}
|
required={isRequired}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
disabled={isDisabled}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
leftIcon ? 'pl-9' : 'pl-4',
|
leftIcon ? 'pl-9' : 'pl-2.5',
|
||||||
rightIcon ? 'pr-9' : 'pr-4',
|
rightIcon ? 'pr-9' : 'pr-2.5',
|
||||||
inputVariants({ className, isError, size, isRounded, variant })
|
inputVariants({ className, isError, size, isRounded, variant })
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,33 +11,34 @@ export type ModalContentProps = DialogPrimitive.DialogContentProps & {
|
|||||||
title?: ReactNode;
|
title?: ReactNode;
|
||||||
subTitle?: string;
|
subTitle?: string;
|
||||||
footerContent?: ReactNode;
|
footerContent?: ReactNode;
|
||||||
|
onClose?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
||||||
({ children, title, subTitle, className, footerContent, ...props }, forwardedRef) => (
|
({ children, title, subTitle, className, footerContent, onClose, ...props }, forwardedRef) => (
|
||||||
<DialogPrimitive.Portal>
|
<DialogPrimitive.Portal>
|
||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
className="fixed inset-0 w-full h-full animate-fadeIn"
|
className="fixed inset-0 h-full w-full animate-fadeIn"
|
||||||
style={{ backgroundColor: 'rgba(0, 0, 0, 0.5)' }}
|
style={{ backgroundColor: 'rgba(0, 0, 0, 0.7)' }}
|
||||||
/>
|
/>
|
||||||
<DialogPrimitive.Content {...props} ref={forwardedRef}>
|
<DialogPrimitive.Content {...props} ref={forwardedRef}>
|
||||||
<Card
|
<Card
|
||||||
isRounded
|
isRounded
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'fixed max-w-md animate-popIn top-1/2 left-1/2 -translate-y-2/4 -translate-x-2/4',
|
'fixed top-1/2 left-1/2 max-w-lg -translate-y-2/4 -translate-x-2/4 animate-popIn drop-shadow-md',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{title && <CardTitle subTitle={subTitle}>{title}</CardTitle>}
|
{title && <CardTitle subTitle={subTitle}>{title}</CardTitle>}
|
||||||
<CardBody>{children}</CardBody>
|
<CardBody>{children}</CardBody>
|
||||||
{footerContent && <CardFooter>{footerContent}</CardFooter>}
|
{footerContent && <CardFooter>{footerContent}</CardFooter>}
|
||||||
<DialogPrimitive.Close aria-label="Close" asChild>
|
<DialogPrimitive.Close aria-label="Close" asChild onClick={onClose}>
|
||||||
<IconButton
|
<IconButton
|
||||||
variant="plain"
|
variant="plain"
|
||||||
ariaLabel="close"
|
ariaLabel="close"
|
||||||
className="absolute top-2.5 right-2.5 text-white hover:bg-gray-600 rounded"
|
className="absolute top-3 right-3 rounded text-white hover:bg-gray-600"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faTimes} size="sm" className="cursor-pointer" />
|
<FontAwesomeIcon icon={faTimes} size="lg" className="cursor-pointer" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -55,3 +56,6 @@ export const Modal = ({ isOpen, ...props }: ModalProps) => (
|
|||||||
|
|
||||||
export const ModalTrigger = DialogPrimitive.Trigger;
|
export const ModalTrigger = DialogPrimitive.Trigger;
|
||||||
export type ModalTriggerProps = DialogPrimitive.DialogTriggerProps;
|
export type ModalTriggerProps = DialogPrimitive.DialogTriggerProps;
|
||||||
|
|
||||||
|
export const ModalClose = DialogPrimitive.Close;
|
||||||
|
export type ModalCloseProps = DialogPrimitive.DialogCloseProps;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export type { ModalContentProps, ModalProps, ModalTriggerProps } from './Modal';
|
export type { ModalCloseProps, ModalContentProps, ModalProps, ModalTriggerProps } from './Modal';
|
||||||
export { Modal, ModalContent, ModalTrigger } from './Modal';
|
export { Modal, ModalClose, ModalContent, ModalTrigger } from './Modal';
|
||||||
|
|||||||
@@ -10,34 +10,40 @@ type Props = {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
dropdownContainerClassName?: string;
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SelectProps = SelectPrimitive.SelectProps & Props;
|
export type SelectProps = SelectPrimitive.SelectProps & Props;
|
||||||
|
|
||||||
export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
export const Select = forwardRef<HTMLButtonElement, SelectProps>(
|
||||||
({ children, placeholder, className, isLoading, ...props }, ref): JSX.Element => {
|
(
|
||||||
|
{ children, placeholder, className, isLoading, dropdownContainerClassName, ...props },
|
||||||
|
ref
|
||||||
|
): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<SelectPrimitive.Root {...props}>
|
<SelectPrimitive.Root {...props}>
|
||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
`inline-flex items-center justify-between data-[placeholder]:text-gray-500
|
`inline-flex items-center justify-between rounded-md
|
||||||
px-3 py-2 font-inter text-sm text-bunker-200 font-normal rounded-md bg-mineshaft-800 outline-none`,
|
bg-bunker-800 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-gray-500`,
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<SelectPrimitive.Value placeholder={placeholder} />
|
<SelectPrimitive.Value placeholder={placeholder} />
|
||||||
{!props.disabled && <SelectPrimitive.Icon className="ml-3">
|
{!props.disabled && (
|
||||||
|
<SelectPrimitive.Icon className="ml-3">
|
||||||
<FontAwesomeIcon icon={faChevronDown} size="sm" />
|
<FontAwesomeIcon icon={faChevronDown} size="sm" />
|
||||||
</SelectPrimitive.Icon>}
|
</SelectPrimitive.Icon>
|
||||||
|
)}
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
<SelectPrimitive.Portal>
|
<SelectPrimitive.Portal>
|
||||||
<SelectPrimitive.Content
|
<SelectPrimitive.Content
|
||||||
// position="popper"
|
className={twMerge(
|
||||||
sideOffset={4}
|
'relative left-4 top-1 overflow-hidden rounded-md bg-bunker-800 font-inter text-bunker-100 shadow-md',
|
||||||
className="overflow-hidden text-bunker-100 rounded-md shadow-md font-inter bg-mineshaft-800"
|
dropdownContainerClassName
|
||||||
style={{ width: 'var(--radix-select-trigger-width) + 6' }}
|
)}
|
||||||
>
|
>
|
||||||
<SelectPrimitive.ScrollUpButton>
|
<SelectPrimitive.ScrollUpButton>
|
||||||
<FontAwesomeIcon icon={faChevronUp} size="sm" />
|
<FontAwesomeIcon icon={faChevronUp} size="sm" />
|
||||||
@@ -75,11 +81,11 @@ export const SelectItem = forwardRef<HTMLDivElement, SelectItemProps>(
|
|||||||
<SelectPrimitive.Item
|
<SelectPrimitive.Item
|
||||||
{...props}
|
{...props}
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
`text-sm rounded-sm transition-all hover:bg-mineshaft-500
|
`relative flex cursor-pointer
|
||||||
flex items-center pl-10 pr-4 py-2 cursor-pointer rounded-md
|
select-none items-center rounded-md py-2 pl-10 pr-4 text-sm
|
||||||
select-none outline-none relative`,
|
outline-none transition-all hover:bg-mineshaft-500`,
|
||||||
isSelected && 'bg-primary',
|
isSelected && 'bg-primary',
|
||||||
isDisabled && 'text-gray-600 hover:bg-transparent cursor-not-allowed hover:text-gray-600',
|
isDisabled && 'cursor-not-allowed text-gray-600 hover:bg-transparent hover:text-gray-600',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
ref={forwardedRef}
|
ref={forwardedRef}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ReactNode } from 'react';
|
import { HTMLAttributes, ReactNode, TdHTMLAttributes } from 'react';
|
||||||
import { twMerge } from 'tailwind-merge';
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
export type TableContainerProps = {
|
export type TableContainerProps = {
|
||||||
@@ -14,7 +14,7 @@ export const TableContainer = ({
|
|||||||
}: TableContainerProps): JSX.Element => (
|
}: TableContainerProps): JSX.Element => (
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'overflow-x-auto font-inter shadow-md relative border border-solid border-mineshaft-700',
|
'relative w-full overflow-x-auto border border-solid border-mineshaft-700 font-inter shadow-md',
|
||||||
isRounded && 'rounded-md',
|
isRounded && 'rounded-md',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
@@ -32,7 +32,7 @@ export type TableProps = {
|
|||||||
export const Table = ({ children, className }: TableProps): JSX.Element => (
|
export const Table = ({ children, className }: TableProps): JSX.Element => (
|
||||||
<table
|
<table
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
'bg-bunker-800 p-2 roun text-gray-300 w-full text-sm text-left rounded-md',
|
'w-full rounded rounded-md bg-bunker-800 p-2 text-left text-sm text-gray-300',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -47,7 +47,7 @@ export type THeadProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const THead = ({ children, className }: THeadProps): JSX.Element => (
|
export const THead = ({ children, className }: THeadProps): JSX.Element => (
|
||||||
<thead className={twMerge('text-xs bg-bunker text-bunker-300 uppercase', className)}>
|
<thead className={twMerge('bg-bunker text-xs uppercase text-bunker-300', className)}>
|
||||||
{children}
|
{children}
|
||||||
</thead>
|
</thead>
|
||||||
);
|
);
|
||||||
@@ -56,20 +56,22 @@ export const THead = ({ children, className }: THeadProps): JSX.Element => (
|
|||||||
export type TrProps = {
|
export type TrProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
} & HTMLAttributes<HTMLTableRowElement>;
|
||||||
|
|
||||||
export const Tr = ({ children, className }: TrProps): JSX.Element => (
|
export const Tr = ({ children, className, ...props }: TrProps): JSX.Element => (
|
||||||
<tr className={twMerge('border border-solid border-mineshaft-700', className)}>{children}</tr>
|
<tr className={twMerge('border border-solid border-mineshaft-700 hover:bg-bunker-700', className)} {...props}>
|
||||||
|
{children}
|
||||||
|
</tr>
|
||||||
);
|
);
|
||||||
|
|
||||||
// table head columns
|
// table head columns
|
||||||
export type ThProps = {
|
export type ThProps = {
|
||||||
children: ReactNode;
|
children?: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Th = ({ children, className }: ThProps): JSX.Element => (
|
export const Th = ({ children, className }: ThProps): JSX.Element => (
|
||||||
<th className={twMerge('px-6 py-3 font-medium', className)}>{children}</th>
|
<th className={twMerge('px-5 pt-4 pb-3.5 font-medium font-semibold bg-bunker-500', className)}>{children}</th>
|
||||||
);
|
);
|
||||||
|
|
||||||
// table body
|
// table body
|
||||||
@@ -84,10 +86,12 @@ export const TBody = ({ children, className }: TBodyProps): JSX.Element => (
|
|||||||
|
|
||||||
// table body columns
|
// table body columns
|
||||||
export type TdProps = {
|
export type TdProps = {
|
||||||
children: ReactNode;
|
children?: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
} & TdHTMLAttributes<HTMLTableCellElement>;
|
||||||
|
|
||||||
export const Td = ({ children, className }: TdProps): JSX.Element => (
|
export const Td = ({ children, className, ...props }: TdProps): JSX.Element => (
|
||||||
<td className={twMerge('text-left px-6 py-3', className)}>{children}</td>
|
<td className={twMerge('px-5 py-2 text-left', className)} {...props}>
|
||||||
|
{children}
|
||||||
|
</td>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
import { Button } from '../Button';
|
||||||
|
import { Modal, ModalClose, ModalContent } from '../Modal';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isOpen?: boolean;
|
||||||
|
onOpenChange?: (isOpen: boolean) => void;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const UpgradePlanModal = ({ text, isOpen, onOpenChange }: Props): JSX.Element => (
|
||||||
|
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
||||||
|
<ModalContent
|
||||||
|
title="Unleash Infisical's Full Power"
|
||||||
|
footerContent={[
|
||||||
|
<Link
|
||||||
|
href={`/settings/billing/${localStorage.getItem('projectData.id') as string}`}
|
||||||
|
key="upgrade-plan"
|
||||||
|
>
|
||||||
|
<Button className="mr-4">Upgrade Plan</Button>
|
||||||
|
</Link>,
|
||||||
|
<ModalClose asChild key="upgrade-plan-cancel">
|
||||||
|
<Button colorSchema="secondary" variant="plain">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</ModalClose>
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<p className="mb-4 text-bunker-300">{text}</p>
|
||||||
|
<p className="font-medium text-bunker-300">
|
||||||
|
Upgrade and get access to this, as well as to other powerful enhancements.
|
||||||
|
</p>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { UpgradePlanModal } from './UpgradePlanModal';
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export * from './Button';
|
export * from './Button';
|
||||||
export * from './Card';
|
export * from './Card';
|
||||||
export * from './Checkbox';
|
export * from './Checkbox';
|
||||||
|
export * from './DeleteActionModal';
|
||||||
export * from './Dropdown';
|
export * from './Dropdown';
|
||||||
export * from './FormControl';
|
export * from './FormControl';
|
||||||
export * from './IconButton';
|
export * from './IconButton';
|
||||||
@@ -12,3 +13,4 @@ export * from './Spinner';
|
|||||||
export * from './Switch';
|
export * from './Switch';
|
||||||
export * from './Table';
|
export * from './Table';
|
||||||
export * from './TextArea';
|
export * from './TextArea';
|
||||||
|
export * from './UpgradePlanModal';
|
||||||
|
|||||||
+24
-4
@@ -16,11 +16,31 @@ export const publicPaths = [
|
|||||||
`/terms`,
|
`/terms`,
|
||||||
`/subprocessors`,
|
`/subprocessors`,
|
||||||
`/verify-email`,
|
`/verify-email`,
|
||||||
`/password-reset`,
|
`/password-reset`
|
||||||
];
|
];
|
||||||
|
|
||||||
export const languageMap = {
|
export const languageMap = {
|
||||||
en: "English",
|
en: 'English',
|
||||||
ko: "한국어",
|
ko: '한국어',
|
||||||
fr: "Français",
|
fr: 'Français'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface Mapping {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const plansDev: Mapping = {
|
||||||
|
starter: 'prod_Mb4ATFT5QAHoPM',
|
||||||
|
team: 'prod_NEpD2WMXUS2eDn',
|
||||||
|
professional: 'prod_Mb4CetZ2jE7jdl',
|
||||||
|
enterprise: 'licence_key_required'
|
||||||
|
};
|
||||||
|
|
||||||
|
const plansProd: Mapping = {
|
||||||
|
starter: 'prod_Mb8oR5XNwyFTul',
|
||||||
|
team: 'prod_NEp7fAB3UJWK6A',
|
||||||
|
professional: 'prod_Mb8pUIpA0OUi5N',
|
||||||
|
enterprise: 'licence_key_required'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const plans = plansProd || plansDev;
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { createContext, ReactNode, useContext, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { useGetOrgSubscription } from '@app/hooks/api';
|
||||||
|
import { GetSubscriptionPlan } from '@app/hooks/api/types';
|
||||||
|
|
||||||
|
import { useWorkspace } from '../WorkspaceContext';
|
||||||
|
// import { Subscription } from '@app/hooks/api/workspace/types';
|
||||||
|
|
||||||
|
type TSubscriptionContext = {
|
||||||
|
subscription?: GetSubscriptionPlan;
|
||||||
|
subscriptionPlan: string;
|
||||||
|
isLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubscriptionContext = createContext<TSubscriptionContext | null>(null);
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SubscriptionProvider = ({ children }: Props): JSX.Element => {
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
const { data, isLoading } = useGetOrgSubscription({
|
||||||
|
orgID: currentWorkspace?.organization || ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// memorize the workspace details for the context
|
||||||
|
const value = useMemo<TSubscriptionContext>(
|
||||||
|
() => ({
|
||||||
|
subscription: data,
|
||||||
|
subscriptionPlan: data?.data?.[0]?.plan?.product || '',
|
||||||
|
isLoading
|
||||||
|
}),
|
||||||
|
[data, isLoading]
|
||||||
|
);
|
||||||
|
|
||||||
|
return <SubscriptionContext.Provider value={value}>{children}</SubscriptionContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useSubscription = () => {
|
||||||
|
const ctx = useContext(SubscriptionContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error('useSubscription has to be used within <SubscriptionContext.Provider>');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { SubscriptionProvider, useSubscription } from './SubscriptionContext';
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { createContext, ReactNode, useContext, useEffect, useMemo } from 'react';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
import { useGetUserWorkspaces } from '@app/hooks/api';
|
||||||
|
import { Workspace } from '@app/hooks/api/workspace/types';
|
||||||
|
|
||||||
|
type TWorkspaceContext = {
|
||||||
|
workspaces: Workspace[];
|
||||||
|
currentWorkspace?: Workspace;
|
||||||
|
isLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const WorkspaceContext = createContext<TWorkspaceContext | null>(null);
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WorkspaceProvider = ({ children }: Props): JSX.Element => {
|
||||||
|
const { data: ws, isLoading } = useGetUserWorkspaces();
|
||||||
|
const router = useRouter();
|
||||||
|
const workspaceId = router.query.id;
|
||||||
|
|
||||||
|
// memorize the workspace details for the context
|
||||||
|
const value = useMemo<TWorkspaceContext>(() => {
|
||||||
|
return {
|
||||||
|
workspaces: ws || [],
|
||||||
|
currentWorkspace: (ws || []).find(({ _id: id }) => id === workspaceId),
|
||||||
|
isLoading
|
||||||
|
};
|
||||||
|
}, [ws, workspaceId, isLoading]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// not loading and current workspace is empty
|
||||||
|
// ws empty means user has no access to the ws
|
||||||
|
// push to the first workspace
|
||||||
|
if (!isLoading && !value?.currentWorkspace?._id) {
|
||||||
|
router.push(`/dashboard/${value.workspaces?.[0]?._id}`);
|
||||||
|
}
|
||||||
|
}, [value?.currentWorkspace?._id, isLoading, value.workspaces?.[0]?._id, router.pathname]);
|
||||||
|
|
||||||
|
return <WorkspaceContext.Provider value={value}>{children}</WorkspaceContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useWorkspace = () => {
|
||||||
|
const ctx = useContext(WorkspaceContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error('useWorkspace has to be used within <WorkspaceContext.Provider>');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { useWorkspace, WorkspaceProvider } from './WorkspaceContext';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { SubscriptionProvider, useSubscription } from './SubscriptionContext';
|
||||||
|
export { useWorkspace, WorkspaceProvider } from './WorkspaceContext';
|
||||||
@@ -1 +1,5 @@
|
|||||||
export { useGetAuthToken } from './auth';
|
export * from './auth';
|
||||||
|
export * from './keys';
|
||||||
|
export * from './serviceTokens';
|
||||||
|
export * from './subscriptions';
|
||||||
|
export * from './workspace';
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export { useGetUserWsKey } from './queries';
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { apiRequest } from '@app/config/request';
|
||||||
|
|
||||||
|
import { UserWsKeyPair } from './types';
|
||||||
|
|
||||||
|
const encKeyKeys = {
|
||||||
|
getUserWorkspaceKey: (workspaceID: string) => ['worksapce-key-pair', { workspaceID }] as const
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchUserWsKey = async (workspaceID: string) => {
|
||||||
|
const { data } = await apiRequest.get<{ latestKey: UserWsKeyPair }>(
|
||||||
|
`/api/v1/key/${workspaceID}/latest`
|
||||||
|
);
|
||||||
|
|
||||||
|
return data.latestKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetUserWsKey = (workspaceID: string) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: encKeyKeys.getUserWorkspaceKey(workspaceID),
|
||||||
|
queryFn: () => fetchUserWsKey(workspaceID),
|
||||||
|
enabled: Boolean(workspaceID)
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
export type UserWsKeyPair = {
|
||||||
|
_id: string;
|
||||||
|
encryptedKey: string;
|
||||||
|
nonce: string;
|
||||||
|
sender: Sender;
|
||||||
|
receiver: string;
|
||||||
|
workspace: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
__v: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Sender = {
|
||||||
|
_id: string;
|
||||||
|
email: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
__v: number;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
publicKey: string;
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { useCreateServiceToken, useDeleteServiceToken, useGetUserWsServiceTokens } from './queries';
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { apiRequest } from '@app/config/request';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CreateServiceTokenDTO,
|
||||||
|
CreateServiceTokenRes,
|
||||||
|
DeleteServiceTokenRes,
|
||||||
|
ServiceToken
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
const serviceTokenKeys = {
|
||||||
|
getAllWorkspaceServiceToken: (workspaceID: string) => [{ workspaceID }, 'service-tokens'] as const
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchWorkspaceServiceTokens = async (workspaceID: string) => {
|
||||||
|
const { data } = await apiRequest.get<{ serviceTokenData: ServiceToken[] }>(
|
||||||
|
`/api/v2/workspace/${workspaceID}/service-token-data`
|
||||||
|
);
|
||||||
|
|
||||||
|
return data.serviceTokenData;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseGetWorkspaceServiceTokensProps = { workspaceID: string };
|
||||||
|
|
||||||
|
export const useGetUserWsServiceTokens = ({ workspaceID }: UseGetWorkspaceServiceTokensProps) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: serviceTokenKeys.getAllWorkspaceServiceToken(workspaceID),
|
||||||
|
queryFn: () => fetchWorkspaceServiceTokens(workspaceID),
|
||||||
|
enabled: Boolean(workspaceID)
|
||||||
|
});
|
||||||
|
|
||||||
|
// mutation
|
||||||
|
export const useCreateServiceToken = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<CreateServiceTokenRes, {}, CreateServiceTokenDTO>({
|
||||||
|
mutationFn: async (body) => {
|
||||||
|
const { data } = await apiRequest.post('/api/v2/service-token/', body);
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
onSuccess: ({ serviceTokenData: { workspace } }) => {
|
||||||
|
queryClient.invalidateQueries(serviceTokenKeys.getAllWorkspaceServiceToken(workspace));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteServiceToken = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<DeleteServiceTokenRes, {}, string>({
|
||||||
|
mutationFn: async (serviceTokenId) => {
|
||||||
|
const { data } = await apiRequest.delete(`/api/v2/service-token/${serviceTokenId}`);
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
onSuccess: ({ serviceTokenData: { workspace } }) => {
|
||||||
|
queryClient.invalidateQueries(serviceTokenKeys.getAllWorkspaceServiceToken(workspace));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
export type ServiceToken = {
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
workspace: string;
|
||||||
|
environment: string;
|
||||||
|
user: string;
|
||||||
|
expiresAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
__v: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateServiceTokenDTO = {
|
||||||
|
name: string;
|
||||||
|
workspaceId: string;
|
||||||
|
environment: string;
|
||||||
|
expiresIn: number;
|
||||||
|
encryptedKey: string;
|
||||||
|
iv: string;
|
||||||
|
tag: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CreateServiceTokenRes = {
|
||||||
|
serviceToken: string;
|
||||||
|
serviceTokenData: ServiceToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeleteServiceTokenRes = { serviceTokenData: ServiceToken };
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { useGetOrgSubscription } from './queries';
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { apiRequest } from '@app/config/request';
|
||||||
|
|
||||||
|
import { GetSubscriptionPlan } from './types';
|
||||||
|
|
||||||
|
// import { Workspace } from './types';
|
||||||
|
|
||||||
|
const subscriptionKeys = {
|
||||||
|
getOrgSubsription: (orgID: string) => ['subscription', { orgID }] as const
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchOrgSubscription = async (orgID: string) => {
|
||||||
|
const { data } = await apiRequest.get<{ subscriptions: GetSubscriptionPlan }>(
|
||||||
|
`/api/v1/organization/${orgID}/subscriptions`
|
||||||
|
);
|
||||||
|
|
||||||
|
return data.subscriptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseGetOrgSubscriptionProps = {
|
||||||
|
orgID: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetOrgSubscription = ({ orgID }: UseGetOrgSubscriptionProps) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: subscriptionKeys.getOrgSubsription(orgID),
|
||||||
|
queryFn: () => fetchOrgSubscription(orgID),
|
||||||
|
enabled: Boolean(orgID)
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export type GetSubscriptionPlan = {
|
||||||
|
data: { plan: SubscriptionPlan }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SubscriptionPlan = {
|
||||||
|
id: string;
|
||||||
|
object: string;
|
||||||
|
active: boolean;
|
||||||
|
aggregate_usage: unknown;
|
||||||
|
amount: 1400;
|
||||||
|
amount_decimal: 1400;
|
||||||
|
billing_scheme: string;
|
||||||
|
created: 1674833546;
|
||||||
|
currency: string;
|
||||||
|
interval: string;
|
||||||
|
interval_count: 1;
|
||||||
|
livemode: false;
|
||||||
|
metadata: {};
|
||||||
|
nickname: null;
|
||||||
|
product: string;
|
||||||
|
tiers_mode: unknown;
|
||||||
|
transform_usage: unknown;
|
||||||
|
trial_period_days: unknown;
|
||||||
|
usage_type: string;
|
||||||
|
};
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export type { GetAuthTokenAPI } from './auth/types';
|
||||||
|
export type { UserWsKeyPair } from './keys/types';
|
||||||
|
export type { CreateServiceTokenDTO, ServiceToken } from './serviceTokens/types';
|
||||||
|
export type { GetSubscriptionPlan, SubscriptionPlan } from './subscriptions/types';
|
||||||
|
export type {
|
||||||
|
CreateEnvironmentDTO,
|
||||||
|
DeleteEnvironmentDTO,
|
||||||
|
DeleteWorkspaceDTO,
|
||||||
|
RenameWorkspaceDTO,
|
||||||
|
UpdateEnvironmentDTO,
|
||||||
|
Workspace,
|
||||||
|
WorkspaceEnv
|
||||||
|
} from './workspace/types';
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
export {
|
||||||
|
useCreateWsEnvironment,
|
||||||
|
useDeleteWorkspace,
|
||||||
|
useDeleteWsEnvironment,
|
||||||
|
useGetUserWorkspaces,
|
||||||
|
useRenameWorkspace,
|
||||||
|
useUpdateWsEnvironment
|
||||||
|
} from './queries';
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
import { apiRequest } from '@app/config/request';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CreateEnvironmentDTO,
|
||||||
|
DeleteEnvironmentDTO,
|
||||||
|
DeleteWorkspaceDTO,
|
||||||
|
RenameWorkspaceDTO,
|
||||||
|
UpdateEnvironmentDTO,
|
||||||
|
Workspace
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
const workspaceKeys = {
|
||||||
|
getAllUserWorkspace: ['workspaces'] as const
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchUserWorkspaces = async () => {
|
||||||
|
const { data } = await apiRequest.get<{ workspaces: Workspace[] }>('/api/v1/workspace');
|
||||||
|
|
||||||
|
return data.workspaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetUserWorkspaces = () =>
|
||||||
|
useQuery(workspaceKeys.getAllUserWorkspace, fetchUserWorkspaces);
|
||||||
|
|
||||||
|
// mutation
|
||||||
|
export const useRenameWorkspace = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<{}, {}, RenameWorkspaceDTO>({
|
||||||
|
mutationFn: ({ workspaceID, newWorkspaceName }) =>
|
||||||
|
apiRequest.post(`/api/v1/workspace/${workspaceID}/name`, { name: newWorkspaceName }),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteWorkspace = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<{}, {}, DeleteWorkspaceDTO>({
|
||||||
|
mutationFn: ({ workspaceID }) => apiRequest.delete(`/api/v1/workspace/${workspaceID}`),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useCreateWsEnvironment = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<{}, {}, CreateEnvironmentDTO>({
|
||||||
|
mutationFn: ({ workspaceID, environmentName, environmentSlug }) =>
|
||||||
|
apiRequest.post(`/api/v2/workspace/${workspaceID}/environments`, {
|
||||||
|
environmentName,
|
||||||
|
environmentSlug
|
||||||
|
}),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateWsEnvironment = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<{}, {}, UpdateEnvironmentDTO>({
|
||||||
|
mutationFn: ({ workspaceID, environmentName, environmentSlug, oldEnvironmentSlug }) =>
|
||||||
|
apiRequest.put(`/api/v2/workspace/${workspaceID}/environments`, {
|
||||||
|
environmentName,
|
||||||
|
environmentSlug,
|
||||||
|
oldEnvironmentSlug
|
||||||
|
}),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteWsEnvironment = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation<{}, {}, DeleteEnvironmentDTO>({
|
||||||
|
mutationFn: ({ workspaceID, environmentSlug }) =>
|
||||||
|
apiRequest.delete(`/api/v2/workspace/${workspaceID}/environments`, {
|
||||||
|
data: { environmentSlug }
|
||||||
|
}),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
export type Workspace = {
|
||||||
|
__v: number;
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
organization: string;
|
||||||
|
environments: WorkspaceEnv[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkspaceEnv = { name: string; slug: string };
|
||||||
|
|
||||||
|
// mutation dto
|
||||||
|
export type RenameWorkspaceDTO = { workspaceID: string; newWorkspaceName: string };
|
||||||
|
|
||||||
|
export type DeleteWorkspaceDTO = { workspaceID: string };
|
||||||
|
|
||||||
|
export type CreateEnvironmentDTO = {
|
||||||
|
workspaceID: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
environmentName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateEnvironmentDTO = {
|
||||||
|
workspaceID: string;
|
||||||
|
oldEnvironmentSlug: string;
|
||||||
|
environmentSlug: string;
|
||||||
|
environmentName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DeleteEnvironmentDTO = { workspaceID: string; environmentSlug: string };
|
||||||
@@ -21,7 +21,7 @@ interface UsePopUpReturn<T extends Readonly<string[]> | UsePopUpProps[]> {
|
|||||||
popUp: UsePopUpState<T>;
|
popUp: UsePopUpState<T>;
|
||||||
handlePopUpOpen: (popUpName: keyof UsePopUpState<T>, data?: unknown) => void;
|
handlePopUpOpen: (popUpName: keyof UsePopUpState<T>, data?: unknown) => void;
|
||||||
handlePopUpClose: (popUpName: keyof UsePopUpState<T>) => void;
|
handlePopUpClose: (popUpName: keyof UsePopUpState<T>) => void;
|
||||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<T>) => void;
|
handlePopUpToggle: (popUpName: keyof UsePopUpState<T>, state?: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,10 +50,10 @@ export const usePopUp = <T extends Readonly<string[]> | UsePopUpProps[]>(
|
|||||||
setPopUp((oldState) => ({ ...oldState, [popUpName]: { isOpen: false } }));
|
setPopUp((oldState) => ({ ...oldState, [popUpName]: { isOpen: false } }));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handlePopUpToggle = useCallback((popUpName: keyof UsePopUpState<T>) => {
|
const handlePopUpToggle = useCallback((popUpName: keyof UsePopUpState<T>, state?: boolean) => {
|
||||||
setPopUp((oldState) => ({
|
setPopUp((oldState) => ({
|
||||||
...oldState,
|
...oldState,
|
||||||
[popUpName]: { isOpen: !oldState[popUpName].isOpen }
|
[popUpName]: { isOpen: typeof state === 'undefined' ? !oldState[popUpName].isOpen : state }
|
||||||
}));
|
}));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import Layout from '@app/components/basic/Layout';
|
|||||||
import NotificationProvider from '@app/components/context/Notifications/NotificationProvider';
|
import NotificationProvider from '@app/components/context/Notifications/NotificationProvider';
|
||||||
import Telemetry from '@app/components/utilities/telemetry/Telemetry';
|
import Telemetry from '@app/components/utilities/telemetry/Telemetry';
|
||||||
import { publicPaths } from '@app/const';
|
import { publicPaths } from '@app/const';
|
||||||
|
import { SubscriptionProvider } from '@app/context';
|
||||||
import { AuthProvider } from '@app/context/AuthContext';
|
import { AuthProvider } from '@app/context/AuthContext';
|
||||||
|
import { WorkspaceProvider } from '@app/context/WorkspaceContext';
|
||||||
import { queryClient } from '@app/reactQuery';
|
import { queryClient } from '@app/reactQuery';
|
||||||
|
|
||||||
import '@fortawesome/fontawesome-svg-core/styles.css';
|
import '@fortawesome/fontawesome-svg-core/styles.css';
|
||||||
@@ -68,11 +70,15 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element =>
|
|||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
|
<WorkspaceProvider>
|
||||||
|
<SubscriptionProvider>
|
||||||
<NotificationProvider>
|
<NotificationProvider>
|
||||||
<Layout>
|
<Layout>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</Layout>
|
</Layout>
|
||||||
</NotificationProvider>
|
</NotificationProvider>
|
||||||
|
</SubscriptionProvider>
|
||||||
|
</WorkspaceProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ export default function Activity() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-6 lg:mx-0 w-full overflow-y-scroll h-screen">
|
<div className="mx-6 lg:mx-0 w-full h-screen">
|
||||||
<NavHeader pageName="Project Activity" isProjectRelated />
|
<NavHeader pageName="Project Activity" isProjectRelated />
|
||||||
{currentSidebarAction && (
|
{currentSidebarAction && (
|
||||||
<ActivitySideBar toggleSidebar={toggleSidebar} currentAction={currentSidebarAction} />
|
<ActivitySideBar toggleSidebar={toggleSidebar} currentAction={currentSidebarAction} />
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ export default function Dashboard() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return data ? (
|
return data ? (
|
||||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
<div className="bg-bunker-800 max-h-screen h-full relative flex flex-col justify-between text-white">
|
||||||
<Head>
|
<Head>
|
||||||
<title>{t('common:head-title', { title: t('dashboard:title') })}</title>
|
<title>{t('common:head-title', { title: t('dashboard:title') })}</title>
|
||||||
<link rel="icon" href="/infisical.ico" />
|
<link rel="icon" href="/infisical.ico" />
|
||||||
@@ -526,7 +526,7 @@ export default function Dashboard() {
|
|||||||
<meta property="og:title" content={String(t('dashboard:og-title'))} />
|
<meta property="og:title" content={String(t('dashboard:og-title'))} />
|
||||||
<meta name="og:description" content={String(t('dashboard:og-description'))} />
|
<meta name="og:description" content={String(t('dashboard:og-description'))} />
|
||||||
</Head>
|
</Head>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row h-full">
|
||||||
{sidebarSecretId !== 'None' && (
|
{sidebarSecretId !== 'None' && (
|
||||||
<SideBar
|
<SideBar
|
||||||
toggleSidebar={toggleSidebar}
|
toggleSidebar={toggleSidebar}
|
||||||
|
|||||||
@@ -1,332 +1,28 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import { useTranslation } from 'next-i18next';
|
|
||||||
import { faCheck, faCopy, faPlus } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
|
|
||||||
import Button from '@app/components/basic/buttons/Button';
|
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||||
import AddServiceTokenDialog from '@app/components/basic/dialog/AddServiceTokenDialog';
|
import { ProjectSettingsPage } from '@app/views/Settings/ProjectSettingsPage';
|
||||||
import InputField from '@app/components/basic/InputField';
|
|
||||||
import EnvironmentTable from '@app/components/basic/table/EnvironmentsTable';
|
|
||||||
import ServiceTokenTable from '@app/components/basic/table/ServiceTokenTable';
|
|
||||||
import NavHeader from '@app/components/navigation/NavHeader';
|
|
||||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
|
||||||
import deleteEnvironment from '@app/pages/api/environments/deleteEnvironment';
|
|
||||||
import updateEnvironment from '@app/pages/api/environments/updateEnvironment';
|
|
||||||
|
|
||||||
import createEnvironment from '../../api/environments/createEnvironment';
|
|
||||||
import getServiceTokens from '../../api/serviceToken/getServiceTokens';
|
|
||||||
import deleteWorkspace from '../../api/workspace/deleteWorkspace';
|
|
||||||
import getWorkspaces from '../../api/workspace/getWorkspaces';
|
|
||||||
import renameWorkspace from '../../api/workspace/renameWorkspace';
|
|
||||||
|
|
||||||
type EnvData = {
|
|
||||||
name: string;
|
|
||||||
slug: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function SettingsBasic() {
|
|
||||||
const [buttonReady, setButtonReady] = useState(false);
|
|
||||||
const router = useRouter();
|
|
||||||
const [workspaceName, setWorkspaceName] = useState('');
|
|
||||||
const [serviceTokens, setServiceTokens] = useState<any[]>([]);
|
|
||||||
const [environments, setEnvironments] = useState<Array<EnvData>>([]);
|
|
||||||
const [workspaceToBeDeletedName, setWorkspaceToBeDeletedName] = useState('');
|
|
||||||
// const [isAddOpen, setIsAddOpen] = useState(false);
|
|
||||||
const [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] = useState(false);
|
|
||||||
const [projectIdCopied, setProjectIdCopied] = useState(false);
|
|
||||||
const workspaceId = router.query.id as string;
|
|
||||||
|
|
||||||
|
const ProjectSettings = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
/**
|
|
||||||
* This function copies the project id to the clipboard
|
|
||||||
*/
|
|
||||||
function copyToClipboard() {
|
|
||||||
const copyText = document.getElementById('myInput') as HTMLInputElement;
|
|
||||||
|
|
||||||
if (copyText) {
|
|
||||||
copyText.select();
|
|
||||||
copyText.setSelectionRange(0, 99999); // For mobile devices
|
|
||||||
|
|
||||||
navigator.clipboard.writeText(copyText.value);
|
|
||||||
|
|
||||||
setProjectIdCopied(true);
|
|
||||||
setTimeout(() => setProjectIdCopied(false), 2000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const load = async () => {
|
|
||||||
const userWorkspaces = await getWorkspaces();
|
|
||||||
userWorkspaces.forEach((userWorkspace) => {
|
|
||||||
if (userWorkspace._id === workspaceId) {
|
|
||||||
setWorkspaceName(userWorkspace.name);
|
|
||||||
setEnvironments(userWorkspace.environments);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const tempServiceTokens = await getServiceTokens({
|
|
||||||
workspaceId
|
|
||||||
});
|
|
||||||
setServiceTokens(tempServiceTokens);
|
|
||||||
};
|
|
||||||
|
|
||||||
load();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const modifyWorkspaceName = (newName: string) => {
|
|
||||||
setButtonReady(true);
|
|
||||||
setWorkspaceName(newName);
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitChanges = (newWorkspaceName: string) => {
|
|
||||||
renameWorkspace(workspaceId, newWorkspaceName);
|
|
||||||
setButtonReady(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const closeAddServiceTokenModal = () => {
|
|
||||||
setIsAddServiceTokenDialogOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function deleted a workspace.
|
|
||||||
* It first checks if there is more than one workspace aviable. Otherwise, it doesn't delete
|
|
||||||
* It then checks if the name of the workspace to be deleted is correct. Otherwise, it doesn't delete.
|
|
||||||
* It then deletes the workspace and forwards the user to another aviable workspace.
|
|
||||||
*/
|
|
||||||
const executeDeletingWorkspace = async () => {
|
|
||||||
const userWorkspaces = await getWorkspaces();
|
|
||||||
|
|
||||||
if (userWorkspaces.length > 1) {
|
|
||||||
if (
|
|
||||||
userWorkspaces.filter((workspace) => workspace._id === workspaceId)[0].name ===
|
|
||||||
workspaceToBeDeletedName
|
|
||||||
) {
|
|
||||||
await deleteWorkspace(workspaceId);
|
|
||||||
const ws = await getWorkspaces();
|
|
||||||
router.push(`/dashboard/${ws[0]._id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCreateEnvironment = async ({ name, slug }: EnvData) => {
|
|
||||||
const res = await createEnvironment(workspaceId, {
|
|
||||||
environmentName: name,
|
|
||||||
environmentSlug: slug
|
|
||||||
});
|
|
||||||
if (res) {
|
|
||||||
// TODO: on react-query migration do an api call to resync
|
|
||||||
setEnvironments((env) => [...env, { name, slug }]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onUpdateEnvironment = async (oldSlug: string, { name, slug }: EnvData) => {
|
|
||||||
const res = await updateEnvironment(workspaceId, {
|
|
||||||
oldEnvironmentSlug: oldSlug,
|
|
||||||
environmentName: name,
|
|
||||||
environmentSlug: slug
|
|
||||||
});
|
|
||||||
// TODO: on react-query migration do an api call to resync
|
|
||||||
if (res) {
|
|
||||||
setEnvironments((env) => env.map((el) => (el.slug === oldSlug ? { name, slug } : el)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteEnvironment = async (slugToBeDelete: string) => {
|
|
||||||
const res = await deleteEnvironment(workspaceId, slugToBeDelete);
|
|
||||||
// TODO: on react-query migration do an api call to resync
|
|
||||||
if (res) {
|
|
||||||
setEnvironments((env) => env.filter(({ slug }) => slug !== slugToBeDelete));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{t('common:head-title', { title: t('settings-project:title') })}</title>
|
<title>{t('common:head-title', { title: t('settings-project:title') })}</title>
|
||||||
<link rel="icon" href="/infisical.ico" />
|
<link rel="icon" href="/infisical.ico" />
|
||||||
</Head>
|
</Head>
|
||||||
<AddServiceTokenDialog
|
<ProjectSettingsPage />
|
||||||
isOpen={isAddServiceTokenDialogOpen}
|
</>
|
||||||
workspaceId={workspaceId}
|
|
||||||
environments={environments}
|
|
||||||
closeModal={closeAddServiceTokenModal}
|
|
||||||
workspaceName={workspaceName}
|
|
||||||
serviceTokens={serviceTokens}
|
|
||||||
setServiceTokens={setServiceTokens}
|
|
||||||
/>
|
|
||||||
<div className="flex flex-row mr-6 max-w-5xl">
|
|
||||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
|
||||||
<NavHeader pageName={t('settings-project:title')} isProjectRelated />
|
|
||||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
|
||||||
<div className="flex flex-col justify-start items-start text-3xl">
|
|
||||||
<p className="font-semibold mr-4 text-gray-200">{t('settings-project:title')}</p>
|
|
||||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
|
||||||
{t('settings-project:description')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col ml-6 text-mineshaft-50">
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<div className="min-w-md mt-2 flex flex-col items-start">
|
|
||||||
<div className="bg-white/5 rounded-md px-6 pb-4 flex flex-col items-start w-full mb-6 pt-2">
|
|
||||||
<p className="text-xl font-semibold mb-4 mt-2">{t('common:display-name')}</p>
|
|
||||||
<div className="max-h-28 w-full max-w-md mr-auto">
|
|
||||||
<InputField
|
|
||||||
label=""
|
|
||||||
onChangeHandler={modifyWorkspaceName}
|
|
||||||
type="varName"
|
|
||||||
value={workspaceName}
|
|
||||||
placeholder=""
|
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex justify-start w-full">
|
|
||||||
<div className="flex justify-start max-w-sm mt-4 mb-2">
|
|
||||||
<Button
|
|
||||||
text={t('common:save-changes') as string}
|
|
||||||
onButtonPressed={() => submitChanges(workspaceName)}
|
|
||||||
color="mineshaft"
|
|
||||||
size="md"
|
|
||||||
active={buttonReady}
|
|
||||||
iconDisabled={faCheck}
|
|
||||||
textDisabled="Saved"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white/5 rounded-md px-6 pt-4 pb-2 flex flex-col items-start w-full mb-6 mt-4">
|
|
||||||
<p className="text-xl font-semibold self-start">{t('common:project-id')}</p>
|
|
||||||
<p className="text-base text-gray-400 font-normal self-start mt-4">
|
|
||||||
{t('settings-project:project-id-description')}
|
|
||||||
</p>
|
|
||||||
<p className="text-base text-gray-400 font-normal self-start">
|
|
||||||
{t('settings-project:project-id-description2')}
|
|
||||||
{/* eslint-disable-next-line react/jsx-no-target-blank */}
|
|
||||||
<a
|
|
||||||
href="https://infisical.com/docs/getting-started/introduction"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
className="text-primary hover:opacity-80 duration-200"
|
|
||||||
>
|
|
||||||
{t('settings-project:docs')}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
<p className="mt-4 text-xs text-bunker-300">
|
|
||||||
{t('settings-project:auto-generated')}
|
|
||||||
</p>
|
|
||||||
<div className="flex justify-end items-center bg-white/[0.07] text-base mt-2 mb-3 mr-2 rounded-md text-gray-400">
|
|
||||||
<p className="mr-2 font-bold pl-4">{`${t('common:project-id')}:`}</p>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={workspaceId}
|
|
||||||
id="myInput"
|
|
||||||
className="bg-white/0 text-gray-400 py-2 w-60 px-2 min-w-md outline-none"
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
<div className="group font-normal group relative inline-block text-gray-400 underline hover:text-primary duration-200">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={copyToClipboard}
|
|
||||||
className="pl-4 pr-4 border-l border-white/20 py-2 hover:bg-white/[0.12] duration-200"
|
|
||||||
>
|
|
||||||
{projectIdCopied ? (
|
|
||||||
<FontAwesomeIcon icon={faCheck} className="pr-0.5" />
|
|
||||||
) : (
|
|
||||||
<FontAwesomeIcon icon={faCopy} />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full pl-3 py-2 bg-bunker-800 rounded-md text-center text-gray-400 text-sm">
|
|
||||||
{t('common:click-to-copy')}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white/5 rounded-md px-6 pt-6 flex flex-col items-start w-full mt-4 mb-4">
|
|
||||||
<EnvironmentTable
|
|
||||||
data={environments}
|
|
||||||
onCreateEnv={onCreateEnvironment}
|
|
||||||
onUpdateEnv={onUpdateEnvironment}
|
|
||||||
onDeleteEnv={onDeleteEnvironment}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white/5 rounded-md px-6 flex flex-col items-start w-full mt-4 mb-4 pt-2">
|
|
||||||
<div className="flex flex-row justify-between w-full">
|
|
||||||
<div className="flex flex-col w-full">
|
|
||||||
<p className="text-xl font-semibold mb-3">
|
|
||||||
{t('section-token:service-tokens')}
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-gray-400">
|
|
||||||
{t('section-token:service-tokens-description')}
|
|
||||||
</p>
|
|
||||||
<p className="text-sm text-gray-400 mb-4">
|
|
||||||
Please, make sure you are on the
|
|
||||||
<a
|
|
||||||
className="text-primary underline underline-offset-2 ml-1"
|
|
||||||
href="https://infisical.com/docs/cli/overview"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
latest version of CLI
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="w-48 mt-2">
|
|
||||||
<Button
|
|
||||||
text={t('section-token:add-new') as string}
|
|
||||||
onButtonPressed={() => {
|
|
||||||
setIsAddServiceTokenDialogOpen(true);
|
|
||||||
}}
|
|
||||||
color="mineshaft"
|
|
||||||
icon={faPlus}
|
|
||||||
size="md"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ServiceTokenTable
|
|
||||||
data={serviceTokens}
|
|
||||||
workspaceName={workspaceName}
|
|
||||||
setServiceTokens={setServiceTokens as any}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white/5 rounded-md px-6 border-l border-red pl-6 flex flex-col items-start w-full mb-6 mt-4 pb-4 pt-2">
|
|
||||||
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
|
|
||||||
<p className="mt-2 text-md text-gray-400">{t('settings-project:danger-zone-note')}</p>
|
|
||||||
<div className="max-h-28 w-full max-w-md mr-auto mt-4">
|
|
||||||
<InputField
|
|
||||||
label={t('settings-project:project-to-delete') as string}
|
|
||||||
onChangeHandler={setWorkspaceToBeDeletedName}
|
|
||||||
type="varName"
|
|
||||||
value={workspaceToBeDeletedName}
|
|
||||||
placeholder=""
|
|
||||||
isRequired
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="max-w-md mt-6 w-full inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2.5 text-sm font-medium text-gray-400 hover:bg-red hover:text-white hover:font-semibold hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
|
||||||
onClick={executeDeletingWorkspace}
|
|
||||||
>
|
|
||||||
{t('settings-project:delete-project')}
|
|
||||||
</button>
|
|
||||||
<p className="mt-0.5 ml-1 text-xs text-gray-500">
|
|
||||||
{t('settings-project:delete-project-note')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
SettingsBasic.requireAuth = true;
|
export default ProjectSettings;
|
||||||
|
|
||||||
export const getServerSideProps = getTranslatedServerSideProps([
|
ProjectSettings.requireAuth = true;
|
||||||
|
|
||||||
|
export const getServerSideProps = getTranslatedStaticProps([
|
||||||
'settings',
|
'settings',
|
||||||
'settings-project',
|
'settings-project',
|
||||||
'section-token'
|
'section-token'
|
||||||
|
|||||||
@@ -0,0 +1,288 @@
|
|||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider';
|
||||||
|
import NavHeader from '@app/components/navigation/NavHeader';
|
||||||
|
// TODO(akhilmhdh):Refactor this into a better utility module package
|
||||||
|
import {
|
||||||
|
decryptAssymmetric,
|
||||||
|
encryptSymmetric
|
||||||
|
} from '@app/components/utilities/cryptography/crypto';
|
||||||
|
import { Button, FormControl, Input } from '@app/components/v2';
|
||||||
|
import { plans } from '@app/const';
|
||||||
|
import { useSubscription, useWorkspace } from '@app/context';
|
||||||
|
import { useToggle } from '@app/hooks';
|
||||||
|
import {
|
||||||
|
useCreateServiceToken,
|
||||||
|
useCreateWsEnvironment,
|
||||||
|
useDeleteServiceToken,
|
||||||
|
useDeleteWorkspace,
|
||||||
|
useDeleteWsEnvironment,
|
||||||
|
useGetUserWsKey,
|
||||||
|
useGetUserWsServiceTokens,
|
||||||
|
useRenameWorkspace,
|
||||||
|
useUpdateWsEnvironment
|
||||||
|
} from '@app/hooks/api';
|
||||||
|
|
||||||
|
import {
|
||||||
|
CopyProjectIDSection,
|
||||||
|
CreateServiceToken,
|
||||||
|
CreateUpdateEnvFormData,
|
||||||
|
EnvironmentSection,
|
||||||
|
ProjectNameChangeSection,
|
||||||
|
ServiceTokenSection
|
||||||
|
} from './components';
|
||||||
|
|
||||||
|
export const ProjectSettingsPage = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
const { data: serviceTokens } = useGetUserWsServiceTokens({
|
||||||
|
workspaceID: currentWorkspace?._id || ''
|
||||||
|
});
|
||||||
|
const workspaceID = currentWorkspace?._id || '';
|
||||||
|
const { createNotification } = useNotificationContext();
|
||||||
|
// delete action worksapce
|
||||||
|
const [deleteProjectInput, setDeleteProjectInput] = useState('');
|
||||||
|
const [isDeleting, setIsDeleting] = useToggle();
|
||||||
|
|
||||||
|
const renameWorkspace = useRenameWorkspace();
|
||||||
|
const deleteWorkspace = useDeleteWorkspace();
|
||||||
|
// env crud operation
|
||||||
|
const createWsEnv = useCreateWsEnvironment();
|
||||||
|
const updateWsEnv = useUpdateWsEnvironment();
|
||||||
|
const deleteWsEnv = useDeleteWsEnvironment();
|
||||||
|
|
||||||
|
// service token
|
||||||
|
const { data: latestFileKey } = useGetUserWsKey(workspaceID);
|
||||||
|
const createServiceToken = useCreateServiceToken();
|
||||||
|
const deleteServiceToken = useDeleteServiceToken();
|
||||||
|
|
||||||
|
// get user subscription
|
||||||
|
const { subscriptionPlan } = useSubscription();
|
||||||
|
const host = window.location.origin;
|
||||||
|
const isEnvServiceAllowed =
|
||||||
|
subscriptionPlan !== plans.starter || host !== 'https://app.infisical.com';
|
||||||
|
|
||||||
|
|
||||||
|
const onRenameWorkspace = async (name: string) => {
|
||||||
|
try {
|
||||||
|
await renameWorkspace.mutateAsync({ workspaceID, newWorkspaceName: name });
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully renamed workspace',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to rename workspace',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteWorkspace = async () => {
|
||||||
|
setIsDeleting.on();
|
||||||
|
try {
|
||||||
|
await deleteWorkspace.mutateAsync({ workspaceID });
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully deleted workspace',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to delete workspace',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsDeleting.off();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// workspace environment operation
|
||||||
|
const onCreateWsEnv = async ({ environmentName, environmentSlug }: CreateUpdateEnvFormData) => {
|
||||||
|
try {
|
||||||
|
await createWsEnv.mutateAsync({ workspaceID, environmentName, environmentSlug });
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully created environment',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to create environment',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onUpdateWsEnv = async (
|
||||||
|
oldEnvironmentSlug: string,
|
||||||
|
{ environmentName, environmentSlug }: CreateUpdateEnvFormData
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
await updateWsEnv.mutateAsync({
|
||||||
|
workspaceID,
|
||||||
|
environmentName,
|
||||||
|
environmentSlug,
|
||||||
|
oldEnvironmentSlug
|
||||||
|
});
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully updated environment',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to update environment',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteWsEnv = async (environmentSlug: string) => {
|
||||||
|
try {
|
||||||
|
await deleteWsEnv.mutateAsync({
|
||||||
|
workspaceID,
|
||||||
|
environmentSlug
|
||||||
|
});
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully deleted environment',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to delete environment',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCreateServiceToken = async ({ environment, expiresIn, name }: CreateServiceToken) => {
|
||||||
|
// type guard
|
||||||
|
if (!latestFileKey) return '';
|
||||||
|
try {
|
||||||
|
// crypo calculation to generate the key
|
||||||
|
const key = decryptAssymmetric({
|
||||||
|
ciphertext: latestFileKey.encryptedKey,
|
||||||
|
nonce: latestFileKey.nonce,
|
||||||
|
publicKey: latestFileKey.sender.publicKey,
|
||||||
|
privateKey: localStorage.getItem('PRIVATE_KEY') as string
|
||||||
|
});
|
||||||
|
const randomBytes = crypto.randomBytes(16).toString('hex');
|
||||||
|
const { ciphertext, iv, tag } = encryptSymmetric({
|
||||||
|
plaintext: key,
|
||||||
|
key: randomBytes
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await createServiceToken.mutateAsync({
|
||||||
|
encryptedKey: ciphertext,
|
||||||
|
iv,
|
||||||
|
tag,
|
||||||
|
environment,
|
||||||
|
expiresIn: Number(expiresIn),
|
||||||
|
name,
|
||||||
|
workspaceId: workspaceID
|
||||||
|
});
|
||||||
|
console.log(res);
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully created a service token',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
return res.serviceToken;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to create a service token',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteServiceToken = async (tokenID: string) => {
|
||||||
|
try {
|
||||||
|
await deleteServiceToken.mutateAsync(tokenID);
|
||||||
|
createNotification({
|
||||||
|
text: 'Successfully revoked service token',
|
||||||
|
type: 'success'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
createNotification({
|
||||||
|
text: 'Failed to delete service token',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto flex flex-col px-8 text-mineshaft-50">
|
||||||
|
{/* TODO(akhilmhdh): Remove this right when layout is refactored */}
|
||||||
|
<div className="relative right-5">
|
||||||
|
<NavHeader pageName={t('settings-project:title')} isProjectRelated />
|
||||||
|
</div>
|
||||||
|
<div className="my-8 flex max-w-5xl flex-row items-center justify-between text-xl">
|
||||||
|
<div className="flex flex-col items-start justify-start text-3xl">
|
||||||
|
<p className="mr-4 font-semibold text-gray-200">{t('settings-project:title')}</p>
|
||||||
|
<p className="mr-4 text-base font-normal text-gray-400">
|
||||||
|
{t('settings-project:description')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ProjectNameChangeSection
|
||||||
|
workspaceName={currentWorkspace?.name}
|
||||||
|
onProjectNameChange={onRenameWorkspace}
|
||||||
|
/>
|
||||||
|
<CopyProjectIDSection workspaceID={currentWorkspace?._id || ''} />
|
||||||
|
<EnvironmentSection
|
||||||
|
environments={currentWorkspace?.environments || []}
|
||||||
|
onCreate={onCreateWsEnv}
|
||||||
|
onDelete={onDeleteWsEnv}
|
||||||
|
onUpdate={onUpdateWsEnv}
|
||||||
|
isEnvServiceAllowed={isEnvServiceAllowed}
|
||||||
|
/>
|
||||||
|
<ServiceTokenSection
|
||||||
|
tokens={serviceTokens || []}
|
||||||
|
environments={currentWorkspace?.environments || []}
|
||||||
|
onDeleteToken={onDeleteServiceToken}
|
||||||
|
workspaceName={currentWorkspace?.name || ''}
|
||||||
|
onCreateToken={onCreateServiceToken}
|
||||||
|
/>
|
||||||
|
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md border-l border-red bg-white/5 px-6 pl-6 pb-4 pt-4">
|
||||||
|
<p className="text-xl font-bold text-red">{t('settings-project:danger-zone')}</p>
|
||||||
|
<p className="text-md mt-2 text-gray-400">{t('settings-project:danger-zone-note')}</p>
|
||||||
|
<div className="mr-auto mt-4 max-h-28 w-full max-w-md">
|
||||||
|
<FormControl
|
||||||
|
label={
|
||||||
|
<div className="mb-0.5 text-sm font-normal text-gray-400">
|
||||||
|
Type <span className="font-bold">{currentWorkspace?.name}</span> to delete the
|
||||||
|
workspace
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
onChange={(e) => setDeleteProjectInput(e.target.value)}
|
||||||
|
value={deleteProjectInput}
|
||||||
|
placeholder="Type the project name to delete"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
colorSchema="danger"
|
||||||
|
onClick={onDeleteWorkspace}
|
||||||
|
isDisabled={deleteProjectInput !== currentWorkspace?.name || isDeleting}
|
||||||
|
isLoading={isDeleting}
|
||||||
|
>
|
||||||
|
{t('settings-project:delete-project')}
|
||||||
|
</Button>
|
||||||
|
<p className="mt-3 ml-0.5 text-xs text-gray-500">
|
||||||
|
{t('settings-project:delete-project-note')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
import { IconButton } from '@app/components/v2';
|
||||||
|
import { useToggle } from '@app/hooks';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
workspaceID: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CopyProjectIDSection = ({ workspaceID }: Props): JSX.Element => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [isProjectIdCopied, setIsProjectIdCopied] = useToggle(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timer: NodeJS.Timeout;
|
||||||
|
if (isProjectIdCopied) {
|
||||||
|
timer = setTimeout(() => setIsProjectIdCopied.off(), 2000);
|
||||||
|
}
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [isProjectIdCopied]);
|
||||||
|
|
||||||
|
const copyProjectIdToClipboard = () => {
|
||||||
|
navigator.clipboard.writeText(workspaceID);
|
||||||
|
setIsProjectIdCopied.on();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-4 pb-2">
|
||||||
|
<p className="self-start text-xl font-semibold">{t('common:project-id')}</p>
|
||||||
|
<p className="mt-4 self-start text-base font-normal text-gray-400">
|
||||||
|
{t('settings-project:project-id-description')}
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 self-start text-base font-normal text-gray-400">
|
||||||
|
{t('settings-project:project-id-description2')}
|
||||||
|
{/* eslint-disable-next-line react/jsx-no-target-blank */}
|
||||||
|
<a
|
||||||
|
href="https://infisical.com/docs/getting-started/introduction"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
className="text-primary duration-200 hover:opacity-80"
|
||||||
|
>
|
||||||
|
{t('settings-project:docs')}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p className="mt-4 text-xs text-bunker-300">{t('settings-project:auto-generated')}</p>
|
||||||
|
<div className="mt-2 mb-3 mr-2 flex items-center justify-end rounded-md bg-white/[0.07] text-base text-gray-400">
|
||||||
|
<p className="mr-2 pl-4 font-bold">{`${t('common:project-id')}:`}</p>
|
||||||
|
<p className="mr-4">{workspaceID}</p>
|
||||||
|
<IconButton
|
||||||
|
ariaLabel="copy icon"
|
||||||
|
colorSchema="secondary"
|
||||||
|
className="group relative"
|
||||||
|
onClick={() => copyProjectIdToClipboard()}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={isProjectIdCopied ? faCheck : faCopy} />
|
||||||
|
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
|
||||||
|
{t('common:click-to-copy')}
|
||||||
|
</span>
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export { CopyProjectIDSection } from './CopyProjectIDSection';
|
||||||
+240
@@ -0,0 +1,240 @@
|
|||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { faPencil, faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import * as yup from 'yup';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DeleteActionModal,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
|
Table,
|
||||||
|
TableContainer,
|
||||||
|
TBody,
|
||||||
|
Td,
|
||||||
|
Th,
|
||||||
|
THead,
|
||||||
|
Tr,
|
||||||
|
UpgradePlanModal
|
||||||
|
} from '@app/components/v2';
|
||||||
|
import { usePopUp } from '@app/hooks/usePopUp';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
environments: Array<{ name: string; slug: string }>;
|
||||||
|
isEnvServiceAllowed: boolean;
|
||||||
|
onCreate: (data: CreateUpdateEnvFormData) => Promise<void>;
|
||||||
|
onUpdate: (oldEnvSlug: string, data: CreateUpdateEnvFormData) => Promise<void>;
|
||||||
|
onDelete: (envSlug: string) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createUpdateEnvSchema = yup.object({
|
||||||
|
environmentName: yup.string().label('Environment Name').required(),
|
||||||
|
environmentSlug: yup.string().label('Environment Slug').required()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CreateUpdateEnvFormData = yup.InferType<typeof createUpdateEnvSchema>;
|
||||||
|
|
||||||
|
export const EnvironmentSection = ({
|
||||||
|
environments,
|
||||||
|
isEnvServiceAllowed,
|
||||||
|
onCreate,
|
||||||
|
onDelete,
|
||||||
|
onUpdate
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||||
|
'createUpdateEnv',
|
||||||
|
'deleteEnv',
|
||||||
|
'upgradePlan'
|
||||||
|
] as const);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
reset,
|
||||||
|
formState: { isSubmitting }
|
||||||
|
} = useForm<CreateUpdateEnvFormData>({
|
||||||
|
resolver: yupResolver(createUpdateEnvSchema)
|
||||||
|
});
|
||||||
|
|
||||||
|
const isEnvUpdate = Boolean(popUp?.createUpdateEnv?.data);
|
||||||
|
const oldEnvSlug = (popUp?.createUpdateEnv?.data as { slug: string })?.slug;
|
||||||
|
|
||||||
|
const onEnvModalSubmit = async (data: CreateUpdateEnvFormData) => {
|
||||||
|
if (isEnvUpdate) {
|
||||||
|
await onUpdate(oldEnvSlug, data);
|
||||||
|
} else {
|
||||||
|
await onCreate(data);
|
||||||
|
}
|
||||||
|
handlePopUpClose('createUpdateEnv');
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEnvDeleteSubmit = async (envSlug: string) => {
|
||||||
|
await onDelete(envSlug);
|
||||||
|
handlePopUpClose('deleteEnv');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-white/5 p-6">
|
||||||
|
<div className="mb-2 flex w-full flex-row justify-between">
|
||||||
|
<div className="flex w-full flex-col">
|
||||||
|
<p className="mb-3 text-xl font-semibold">Project Environments</p>
|
||||||
|
<p className="mb-4 text-base text-gray-400">
|
||||||
|
Choose which environments will show up in your dashboard like development, staging,
|
||||||
|
production
|
||||||
|
</p>
|
||||||
|
<p className="mr-1 self-start text-sm text-gray-500">
|
||||||
|
Note: the text in slugs shows how these environmant should be accessed in CLI.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
if (isEnvServiceAllowed) {
|
||||||
|
handlePopUpOpen('createUpdateEnv');
|
||||||
|
} else {
|
||||||
|
handlePopUpOpen('upgradePlan');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
colorSchema="primary"
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
|
>
|
||||||
|
Add New Env
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<THead>
|
||||||
|
<Tr>
|
||||||
|
<Th>Name</Th>
|
||||||
|
<Th>Slug</Th>
|
||||||
|
<Th aria-label="button" />
|
||||||
|
</Tr>
|
||||||
|
</THead>
|
||||||
|
<TBody>
|
||||||
|
{environments?.length > 0 ? (
|
||||||
|
environments.map(({ name, slug }) => (
|
||||||
|
<Tr key={name}>
|
||||||
|
<Td>{name}</Td>
|
||||||
|
<Td>{slug}</Td>
|
||||||
|
<Td className="flex items-center justify-end">
|
||||||
|
<IconButton
|
||||||
|
className="mr-3"
|
||||||
|
onClick={() => {
|
||||||
|
if (isEnvServiceAllowed) {
|
||||||
|
handlePopUpOpen('createUpdateEnv', { name, slug });
|
||||||
|
reset({ environmentName: name, environmentSlug: slug });
|
||||||
|
} else {
|
||||||
|
handlePopUpOpen('upgradePlan');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
colorSchema="secondary"
|
||||||
|
ariaLabel="update"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faPencil} />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
if (isEnvServiceAllowed) {
|
||||||
|
handlePopUpOpen('deleteEnv', { name, slug });
|
||||||
|
} else {
|
||||||
|
handlePopUpOpen('upgradePlan');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
colorSchema="danger"
|
||||||
|
ariaLabel="update"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faTrashCan} />
|
||||||
|
</IconButton>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Tr>
|
||||||
|
<Td colSpan={4} className="pt-7 pb-5 text-center text-bunker-400">
|
||||||
|
No environments found
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
)}
|
||||||
|
</TBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
<Modal
|
||||||
|
isOpen={popUp?.createUpdateEnv?.isOpen}
|
||||||
|
onOpenChange={(isOpen) => {
|
||||||
|
handlePopUpToggle('createUpdateEnv', isOpen);
|
||||||
|
reset();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ModalContent title={isEnvUpdate ? 'Update environment' : 'Create a new environment'}>
|
||||||
|
<form onSubmit={handleSubmit(onEnvModalSubmit)}>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue=""
|
||||||
|
name="environmentName"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Environment Name"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue=""
|
||||||
|
name="environmentSlug"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Environment Slug"
|
||||||
|
helperText="Slugs are shorthands used in cli to access environment"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="mt-8 flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
isDisabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{isEnvUpdate ? 'Update' : 'Create'}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button colorSchema="secondary" variant="plain">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
<DeleteActionModal
|
||||||
|
isOpen={popUp.deleteEnv.isOpen}
|
||||||
|
title={`Are you sure want to delete ${
|
||||||
|
(popUp?.deleteEnv?.data as { name: string })?.name || ' '
|
||||||
|
}?`}
|
||||||
|
onChange={(isOpen) => handlePopUpToggle('deleteEnv', isOpen)}
|
||||||
|
deleteKey={(popUp?.deleteEnv?.data as { slug: string })?.slug || ''}
|
||||||
|
onDeleteApproved={() =>
|
||||||
|
onEnvDeleteSubmit((popUp?.deleteEnv?.data as { slug: string })?.slug)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<UpgradePlanModal
|
||||||
|
isOpen={popUp.upgradePlan.isOpen}
|
||||||
|
onOpenChange={(isOpen) => handlePopUpToggle('upgradePlan', isOpen)}
|
||||||
|
text="You can add custom environments if you switch to Infisical's Team plan."
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export { EnvironmentSection } from './EnvironmentSection';
|
||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import * as yup from 'yup';
|
||||||
|
|
||||||
|
import { Button, FormControl, Input } from '@app/components/v2';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
workspaceName?: string;
|
||||||
|
onProjectNameChange: (name: string) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const formSchema = yup.object({
|
||||||
|
name: yup.string().required().label('Project Name')
|
||||||
|
});
|
||||||
|
|
||||||
|
type FormData = yup.InferType<typeof formSchema>;
|
||||||
|
|
||||||
|
export const ProjectNameChangeSection = ({
|
||||||
|
workspaceName,
|
||||||
|
onProjectNameChange
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
control,
|
||||||
|
reset,
|
||||||
|
formState: { isDirty, isSubmitting }
|
||||||
|
} = useForm<FormData>({ resolver: yupResolver(formSchema) });
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reset({ name: workspaceName });
|
||||||
|
}, [workspaceName]);
|
||||||
|
|
||||||
|
const onFormSubmit = async ({ name }: FormData) => {
|
||||||
|
await onProjectNameChange(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||||
|
<div className="mb-6 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pb-6 pt-3">
|
||||||
|
<p className="mb-4 mt-2 text-xl font-semibold">{t('common:display-name')}</p>
|
||||||
|
<div className="mb-2 w-full max-w-lg">
|
||||||
|
<Controller
|
||||||
|
defaultValue=""
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||||
|
<Input placeholder="Type your project name" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
control={control}
|
||||||
|
name="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
color="mineshaft"
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
isDisabled={!isDirty || isSubmitting}
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faCheck} />}
|
||||||
|
>
|
||||||
|
{t('common:save-changes')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export { ProjectNameChangeSection } from './ProjectNameChangeSection';
|
||||||
+306
@@ -0,0 +1,306 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { faCheck, faCopy, faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
|
import * as yup from 'yup';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DeleteActionModal,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalClose,
|
||||||
|
ModalContent,
|
||||||
|
ModalTrigger,
|
||||||
|
Select,
|
||||||
|
SelectItem,
|
||||||
|
Table,
|
||||||
|
TableContainer,
|
||||||
|
TBody,
|
||||||
|
Td,
|
||||||
|
Th,
|
||||||
|
THead,
|
||||||
|
Tr
|
||||||
|
} from '@app/components/v2';
|
||||||
|
import { usePopUp, useToggle } from '@app/hooks';
|
||||||
|
import { ServiceToken, WorkspaceEnv } from '@app/hooks/api/types';
|
||||||
|
|
||||||
|
const apiTokenExpiry = [
|
||||||
|
{ label: '1 Day', value: 86400 },
|
||||||
|
{ label: '7 Days', value: 604800 },
|
||||||
|
{ label: '1 Month', value: 2592000 },
|
||||||
|
{ label: '6 months', value: 15552000 },
|
||||||
|
{ label: '12 months', value: 31104000 }
|
||||||
|
];
|
||||||
|
|
||||||
|
const createServiceTokenSchema = yup.object({
|
||||||
|
name: yup.string().required().label('Service Token Name'),
|
||||||
|
environment: yup.string().required().label('Environment'),
|
||||||
|
expiresIn: yup.string().required().label('Service Token Name')
|
||||||
|
});
|
||||||
|
|
||||||
|
export type CreateServiceToken = yup.InferType<typeof createServiceTokenSchema>;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
tokens: ServiceToken[];
|
||||||
|
workspaceName: string;
|
||||||
|
environments: WorkspaceEnv[];
|
||||||
|
onDeleteToken: (serviceTokenID: string) => Promise<void>;
|
||||||
|
onCreateToken: (data: CreateServiceToken) => Promise<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type DeleteModalData = { name: string; id: string };
|
||||||
|
|
||||||
|
export const ServiceTokenSection = ({
|
||||||
|
tokens = [],
|
||||||
|
onDeleteToken,
|
||||||
|
workspaceName,
|
||||||
|
environments = [],
|
||||||
|
onCreateToken
|
||||||
|
}: Props): JSX.Element => {
|
||||||
|
const [newToken, setToken] = useState('');
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [isTokenCopied, setIsTokenCopied] = useToggle(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timer: NodeJS.Timeout;
|
||||||
|
if (isTokenCopied) {
|
||||||
|
timer = setTimeout(() => setIsTokenCopied.off(), 2000);
|
||||||
|
}
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [isTokenCopied]);
|
||||||
|
|
||||||
|
const copyTokenToClipboard = () => {
|
||||||
|
navigator.clipboard.writeText(newToken);
|
||||||
|
setIsTokenCopied.on();
|
||||||
|
};
|
||||||
|
|
||||||
|
const { popUp, handlePopUpToggle, handlePopUpClose, handlePopUpOpen } = usePopUp([
|
||||||
|
'createAPIToken',
|
||||||
|
'deleteAPITokenConfirmation'
|
||||||
|
] as const);
|
||||||
|
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
reset,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting }
|
||||||
|
} = useForm<CreateServiceToken>({
|
||||||
|
resolver: yupResolver(createServiceTokenSchema)
|
||||||
|
});
|
||||||
|
|
||||||
|
const hasServiceToken = Boolean(newToken);
|
||||||
|
|
||||||
|
const onFormSubmit = async (data: CreateServiceToken) => {
|
||||||
|
const token = await onCreateToken(data);
|
||||||
|
setToken(token);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteApproved = async () => {
|
||||||
|
await onDeleteToken((popUp?.deleteAPITokenConfirmation?.data as DeleteModalData)?.id);
|
||||||
|
handlePopUpClose('deleteAPITokenConfirmation');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mt-4 mb-4 flex w-full flex-col items-start rounded-md bg-white/5 p-6">
|
||||||
|
<div className="flex w-full flex-row justify-between">
|
||||||
|
<div className="flex w-full flex-col">
|
||||||
|
<p className="mb-3 text-xl font-semibold">{t('section-token:service-tokens')}</p>
|
||||||
|
<p className="text-sm text-gray-400">{t('section-token:service-tokens-description')}</p>
|
||||||
|
<p className="mb-4 text-sm text-gray-400">
|
||||||
|
Please, make sure you are on the
|
||||||
|
<a
|
||||||
|
className="ml-1 text-primary underline underline-offset-2"
|
||||||
|
href="https://infisical.com/docs/cli/overview"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
latest version of CLI
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
isOpen={popUp?.createAPIToken?.isOpen}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
handlePopUpToggle('createAPIToken', open);
|
||||||
|
reset();
|
||||||
|
setToken('');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ModalTrigger asChild>
|
||||||
|
<Button color="mineshaft" leftIcon={<FontAwesomeIcon icon={faPlus} />}>
|
||||||
|
{t('section-token:add-new')}
|
||||||
|
</Button>
|
||||||
|
</ModalTrigger>
|
||||||
|
<ModalContent
|
||||||
|
title={
|
||||||
|
t('section-token:add-dialog.title', {
|
||||||
|
target: workspaceName
|
||||||
|
}) as string
|
||||||
|
}
|
||||||
|
subTitle={t('section-token:add-dialog.description') as string}
|
||||||
|
>
|
||||||
|
{!hasServiceToken ? (
|
||||||
|
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="name"
|
||||||
|
defaultValue=""
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label={t('section-token:add-dialog.name')}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="Type your token name" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="environment"
|
||||||
|
defaultValue={environments?.[0]?.slug}
|
||||||
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Environment"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
defaultValue={field.value}
|
||||||
|
{...field}
|
||||||
|
onValueChange={(e) => onChange(e)}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{environments.map(({ name, slug }) => (
|
||||||
|
<SelectItem value={slug} key={slug}>
|
||||||
|
{name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="expiresIn"
|
||||||
|
defaultValue={String(apiTokenExpiry?.[0]?.value)}
|
||||||
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Token Expiry"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
defaultValue={field.value}
|
||||||
|
{...field}
|
||||||
|
onValueChange={(e) => onChange(e)}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
{apiTokenExpiry.map(({ label, value }) => (
|
||||||
|
<SelectItem value={String(value)} key={label}>
|
||||||
|
{label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="mt-8 flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
type="submit"
|
||||||
|
isDisabled={isSubmitting}
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
>
|
||||||
|
Create
|
||||||
|
</Button>
|
||||||
|
<ModalClose asChild>
|
||||||
|
<Button variant="plain" colorSchema="secondary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</ModalClose>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<div className="mt-2 mb-3 mr-2 flex items-center justify-end rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
|
||||||
|
<p className="mr-4 break-all">{newToken}</p>
|
||||||
|
<IconButton
|
||||||
|
ariaLabel="copy icon"
|
||||||
|
colorSchema="secondary"
|
||||||
|
className="group relative"
|
||||||
|
onClick={copyTokenToClipboard}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={isTokenCopied ? faCheck : faCopy} />
|
||||||
|
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
|
||||||
|
{t('common:click-to-copy')}
|
||||||
|
</span>
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DeleteActionModal
|
||||||
|
isOpen={popUp.deleteAPITokenConfirmation.isOpen}
|
||||||
|
title={`Delete ${
|
||||||
|
(popUp?.deleteAPITokenConfirmation?.data as DeleteModalData)?.name || ' '
|
||||||
|
} api key?`}
|
||||||
|
onChange={(isOpen) => handlePopUpToggle('deleteAPITokenConfirmation', isOpen)}
|
||||||
|
deleteKey={(popUp?.deleteAPITokenConfirmation?.data as DeleteModalData)?.name}
|
||||||
|
onClose={() => handlePopUpClose('deleteAPITokenConfirmation')}
|
||||||
|
onDeleteApproved={onDeleteApproved}
|
||||||
|
/>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<THead>
|
||||||
|
<Tr>
|
||||||
|
<Th>Token Name</Th>
|
||||||
|
<Th>Environment</Th>
|
||||||
|
<Th>Valid Until</Th>
|
||||||
|
<Th aria-label="button" />
|
||||||
|
</Tr>
|
||||||
|
</THead>
|
||||||
|
<TBody>
|
||||||
|
{tokens?.length > 0 ? (
|
||||||
|
tokens.map((row) => (
|
||||||
|
<Tr key={row._id}>
|
||||||
|
<Td>{row.name}</Td>
|
||||||
|
<Td>{row.environment}</Td>
|
||||||
|
<Td>{new Date(row.expiresAt).toUTCString()}</Td>
|
||||||
|
<Td className="flex items-center justify-end">
|
||||||
|
<IconButton
|
||||||
|
onClick={() =>
|
||||||
|
handlePopUpOpen('deleteAPITokenConfirmation', {
|
||||||
|
name: row.name,
|
||||||
|
id: row._id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
colorSchema="danger"
|
||||||
|
ariaLabel="delete"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faTrashCan} />
|
||||||
|
</IconButton>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Tr>
|
||||||
|
<Td colSpan={4} className="py-6 text-center text-bunker-400">
|
||||||
|
No service tokens found
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
)}
|
||||||
|
</TBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
export {ServiceTokenSection} from './ServiceTokenSection'
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export { CopyProjectIDSection } from './CopyProjectIDSection';
|
||||||
|
export { EnvironmentSection } from './EnvironmentSection';
|
||||||
|
export type { CreateUpdateEnvFormData } from './EnvironmentSection/EnvironmentSection';
|
||||||
|
export { ProjectNameChangeSection } from './ProjectNameChangeSection';
|
||||||
|
export { ServiceTokenSection } from './ServiceTokenSection';
|
||||||
|
export type { CreateServiceToken } from './ServiceTokenSection/ServiceTokenSection';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { ProjectSettingsPage } from './ProjectSettingsPage';
|
||||||
Reference in New Issue
Block a user