mirror of
https://github.com/Infisical/infisical.git
synced 2026-05-02 03:02:03 -04:00
302
backend/package-lock.json
generated
302
backend/package-lock.json
generated
@@ -35,6 +35,8 @@
|
||||
"query-string": "^7.1.3",
|
||||
"rimraf": "^3.0.2",
|
||||
"stripe": "^10.7.0",
|
||||
"swagger-jsdoc": "^6.2.5",
|
||||
"swagger-ui-express": "^4.6.0",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1",
|
||||
"typescript": "^4.9.3",
|
||||
@@ -81,6 +83,46 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/json-schema-ref-parser": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.0.tgz",
|
||||
"integrity": "sha512-teB30tFooE3iQs2HQIKJ02D8UZA1Xy1zaczzhUjJs0CymYxeC0g+y5rCY2p8NHBM6DBUVoR8rSM4kHLj1WE9mQ==",
|
||||
"dependencies": {
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/openapi-schemas": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
|
||||
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/swagger-methods": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
|
||||
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="
|
||||
},
|
||||
"node_modules/@apidevtools/swagger-parser": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz",
|
||||
"integrity": "sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==",
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": "^9.0.6",
|
||||
"@apidevtools/openapi-schemas": "^2.0.4",
|
||||
"@apidevtools/swagger-methods": "^3.0.2",
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"z-schema": "^4.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"openapi-types": ">=7"
|
||||
}
|
||||
},
|
||||
"node_modules/@aws-crypto/ie11-detection": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz",
|
||||
@@ -2571,6 +2613,11 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
|
||||
},
|
||||
"node_modules/@juanelas/base64": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@juanelas/base64/-/base64-1.0.5.tgz",
|
||||
@@ -3147,8 +3194,7 @@
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
|
||||
},
|
||||
"node_modules/@types/jsonwebtoken": {
|
||||
"version": "8.5.9",
|
||||
@@ -3628,8 +3674,7 @@
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
@@ -4013,6 +4058,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/call-me-maybe": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
||||
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -4535,7 +4585,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
@@ -4848,7 +4897,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -6447,7 +6495,6 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
@@ -9789,6 +9836,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi-types": {
|
||||
"version": "12.0.2",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.2.tgz",
|
||||
"integrity": "sha512-GuTo7FyZjOIWVhIhQSWJVaws6A82sWIGyQogxxYBYKZ0NBdyP2CYSIgOwFfSB+UVoPExk/YzFpyYitHS8KVZtA==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
||||
@@ -10935,6 +10988,74 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc": {
|
||||
"version": "6.2.5",
|
||||
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.5.tgz",
|
||||
"integrity": "sha512-l+cdsKS2y+QDhrH1TJSUiE0y9XKuf5xaGSatjf0hR/wjTlMpO8WfubBK9d/nASdbHPMtj9iJZLBH2ogBEhL7Sw==",
|
||||
"dependencies": {
|
||||
"commander": "6.2.0",
|
||||
"doctrine": "3.0.0",
|
||||
"glob": "7.1.6",
|
||||
"lodash.mergewith": "^4.6.2",
|
||||
"swagger-parser": "10.0.2",
|
||||
"yaml": "2.0.0-1"
|
||||
},
|
||||
"bin": {
|
||||
"swagger-jsdoc": "bin/swagger-jsdoc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-jsdoc/node_modules/glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-parser": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.2.tgz",
|
||||
"integrity": "sha512-9jHkHM+QXyLGFLk1DkXBwV+4HyNm0Za3b8/zk/+mjr8jgOSiqm3FOTHBSDsBjtn9scdL+8eWcHdupp2NLM8tDw==",
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/swagger-ui-dist": {
|
||||
"version": "4.15.5",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz",
|
||||
"integrity": "sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA=="
|
||||
},
|
||||
"node_modules/swagger-ui-express": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.0.tgz",
|
||||
"integrity": "sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA==",
|
||||
"dependencies": {
|
||||
"swagger-ui-dist": ">=4.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= v0.10.32"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"express": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/test-exclude": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
|
||||
@@ -11520,6 +11641,14 @@
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.0.0-1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
|
||||
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.6.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
|
||||
@@ -11567,6 +11696,31 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/z-schema": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz",
|
||||
"integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==",
|
||||
"dependencies": {
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"z-schema": "bin/z-schema"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"commander": "^2.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/z-schema/node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -11580,6 +11734,40 @@
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
},
|
||||
"@apidevtools/json-schema-ref-parser": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.0.tgz",
|
||||
"integrity": "sha512-teB30tFooE3iQs2HQIKJ02D8UZA1Xy1zaczzhUjJs0CymYxeC0g+y5rCY2p8NHBM6DBUVoR8rSM4kHLj1WE9mQ==",
|
||||
"requires": {
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"@types/json-schema": "^7.0.6",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"@apidevtools/openapi-schemas": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
|
||||
"integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ=="
|
||||
},
|
||||
"@apidevtools/swagger-methods": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
|
||||
"integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="
|
||||
},
|
||||
"@apidevtools/swagger-parser": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz",
|
||||
"integrity": "sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg==",
|
||||
"requires": {
|
||||
"@apidevtools/json-schema-ref-parser": "^9.0.6",
|
||||
"@apidevtools/openapi-schemas": "^2.0.4",
|
||||
"@apidevtools/swagger-methods": "^3.0.2",
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"call-me-maybe": "^1.0.1",
|
||||
"z-schema": "^4.2.3"
|
||||
}
|
||||
},
|
||||
"@aws-crypto/ie11-detection": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz",
|
||||
@@ -13763,6 +13951,11 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="
|
||||
},
|
||||
"@juanelas/base64": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@juanelas/base64/-/base64-1.0.5.tgz",
|
||||
@@ -14266,8 +14459,7 @@
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
|
||||
},
|
||||
"@types/jsonwebtoken": {
|
||||
"version": "8.5.9",
|
||||
@@ -14615,8 +14807,7 @@
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
@@ -14900,6 +15091,11 @@
|
||||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"call-me-maybe": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
|
||||
"integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="
|
||||
},
|
||||
"callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -15298,7 +15494,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esutils": "^2.0.2"
|
||||
}
|
||||
@@ -15533,8 +15728,7 @@
|
||||
"esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
@@ -16735,7 +16929,6 @@
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
@@ -19125,6 +19318,12 @@
|
||||
"mimic-fn": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"openapi-types": {
|
||||
"version": "12.0.2",
|
||||
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.2.tgz",
|
||||
"integrity": "sha512-GuTo7FyZjOIWVhIhQSWJVaws6A82sWIGyQogxxYBYKZ0NBdyP2CYSIgOwFfSB+UVoPExk/YzFpyYitHS8KVZtA==",
|
||||
"peer": true
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
||||
@@ -19960,6 +20159,55 @@
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true
|
||||
},
|
||||
"swagger-jsdoc": {
|
||||
"version": "6.2.5",
|
||||
"resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.5.tgz",
|
||||
"integrity": "sha512-l+cdsKS2y+QDhrH1TJSUiE0y9XKuf5xaGSatjf0hR/wjTlMpO8WfubBK9d/nASdbHPMtj9iJZLBH2ogBEhL7Sw==",
|
||||
"requires": {
|
||||
"commander": "6.2.0",
|
||||
"doctrine": "3.0.0",
|
||||
"glob": "7.1.6",
|
||||
"lodash.mergewith": "^4.6.2",
|
||||
"swagger-parser": "10.0.2",
|
||||
"yaml": "2.0.0-1"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"swagger-parser": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.2.tgz",
|
||||
"integrity": "sha512-9jHkHM+QXyLGFLk1DkXBwV+4HyNm0Za3b8/zk/+mjr8jgOSiqm3FOTHBSDsBjtn9scdL+8eWcHdupp2NLM8tDw==",
|
||||
"requires": {
|
||||
"@apidevtools/swagger-parser": "10.0.2"
|
||||
}
|
||||
},
|
||||
"swagger-ui-dist": {
|
||||
"version": "4.15.5",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.15.5.tgz",
|
||||
"integrity": "sha512-V3eIa28lwB6gg7/wfNvAbjwJYmDXy1Jo1POjyTzlB6wPcHiGlRxq39TSjYGVjQrUSAzpv+a7nzp7mDxgNy57xA=="
|
||||
},
|
||||
"swagger-ui-express": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.0.tgz",
|
||||
"integrity": "sha512-ZxpQFp1JR2RF8Ar++CyJzEDdvufa08ujNUJgMVTMWPi86CuQeVdBtvaeO/ysrz6dJAYXf9kbVNhWD7JWocwqsA==",
|
||||
"requires": {
|
||||
"swagger-ui-dist": ">=4.11.0"
|
||||
}
|
||||
},
|
||||
"test-exclude": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
|
||||
@@ -20371,6 +20619,11 @@
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"yaml": {
|
||||
"version": "2.0.0-1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
|
||||
"integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "17.6.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
|
||||
@@ -20403,6 +20656,25 @@
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"z-schema": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz",
|
||||
"integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==",
|
||||
"requires": {
|
||||
"commander": "^2.7.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ services:
|
||||
- ./frontend/public:/app/public
|
||||
- ./frontend/styles:/app/styles
|
||||
- ./frontend/components:/app/components
|
||||
- ./frontend/locales:/app/locales
|
||||
- ./frontend/next-i18next.config.js:/app/next-i18next.config.js
|
||||
env_file: .env
|
||||
environment:
|
||||
- NEXT_PUBLIC_ENV=development
|
||||
|
||||
2
frontend/.gitignore
vendored
2
frontend/.gitignore
vendored
@@ -32,3 +32,5 @@ yarn-error.log*
|
||||
.env.production.local
|
||||
.vercel
|
||||
.env.infisical
|
||||
|
||||
.vscode
|
||||
@@ -1,38 +1,39 @@
|
||||
/* eslint-disable no-unexpected-multiline */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { useEffect, useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import {
|
||||
faBookOpen,
|
||||
faGear,
|
||||
faKey,
|
||||
faMobile,
|
||||
faPlug,
|
||||
faUser
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
faUser,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import getOrganizations from '~/pages/api/organization/getOrgs';
|
||||
import getOrganizationUserProjects from '~/pages/api/organization/GetOrgUserProjects';
|
||||
import getOrganizationUsers from '~/pages/api/organization/GetOrgUsers';
|
||||
import checkUserAction from '~/pages/api/userActions/checkUserAction';
|
||||
import addUserToWorkspace from '~/pages/api/workspace/addUserToWorkspace';
|
||||
import createWorkspace from '~/pages/api/workspace/createWorkspace';
|
||||
import getWorkspaces from '~/pages/api/workspace/getWorkspaces';
|
||||
import uploadKeys from '~/pages/api/workspace/uploadKeys';
|
||||
import getOrganizations from "~/pages/api/organization/getOrgs";
|
||||
import getOrganizationUserProjects from "~/pages/api/organization/GetOrgUserProjects";
|
||||
import getOrganizationUsers from "~/pages/api/organization/GetOrgUsers";
|
||||
import checkUserAction from "~/pages/api/userActions/checkUserAction";
|
||||
import addUserToWorkspace from "~/pages/api/workspace/addUserToWorkspace";
|
||||
import createWorkspace from "~/pages/api/workspace/createWorkspace";
|
||||
import getWorkspaces from "~/pages/api/workspace/getWorkspaces";
|
||||
import uploadKeys from "~/pages/api/workspace/uploadKeys";
|
||||
|
||||
import NavBarDashboard from '../navigation/NavBarDashboard';
|
||||
import onboardingCheck from '../utilities/checks/OnboardingCheck';
|
||||
import { tempLocalStorage } from '../utilities/checks/tempLocalStorage';
|
||||
import NavBarDashboard from "../navigation/NavBarDashboard";
|
||||
import onboardingCheck from "../utilities/checks/OnboardingCheck";
|
||||
import { tempLocalStorage } from "../utilities/checks/tempLocalStorage";
|
||||
import {
|
||||
decryptAssymmetric,
|
||||
encryptAssymmetric
|
||||
} from '../utilities/cryptography/crypto';
|
||||
import Button from './buttons/Button';
|
||||
import AddWorkspaceDialog from './dialog/AddWorkspaceDialog';
|
||||
import Listbox from './Listbox';
|
||||
encryptAssymmetric,
|
||||
} from "../utilities/cryptography/crypto";
|
||||
import Button from "./buttons/Button";
|
||||
import AddWorkspaceDialog from "./dialog/AddWorkspaceDialog";
|
||||
import Listbox from "./Listbox";
|
||||
|
||||
interface LayoutProps {
|
||||
children: React.ReactNode;
|
||||
@@ -41,15 +42,17 @@ interface LayoutProps {
|
||||
export default function Layout({ children }: LayoutProps) {
|
||||
const router = useRouter();
|
||||
const [workspaceList, setWorkspaceList] = useState([]);
|
||||
const [workspaceMapping, setWorkspaceMapping] = useState([{ '1': '2' }]);
|
||||
const [workspaceSelected, setWorkspaceSelected] = useState('∞');
|
||||
const [newWorkspaceName, setNewWorkspaceName] = useState('');
|
||||
const [workspaceMapping, setWorkspaceMapping] = useState([{ "1": "2" }]);
|
||||
const [workspaceSelected, setWorkspaceSelected] = useState("∞");
|
||||
const [newWorkspaceName, setNewWorkspaceName] = useState("");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(false);
|
||||
const [totalOnboardingActionsDone, setTotalOnboardingActionsDone] =
|
||||
useState(0);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
function closeModal() {
|
||||
setIsOpen(false);
|
||||
}
|
||||
@@ -75,35 +78,35 @@ export default function Layout({ children }: LayoutProps) {
|
||||
if (!currentWorkspaces.includes(workspaceName)) {
|
||||
const newWorkspace = await createWorkspace({
|
||||
workspaceName,
|
||||
organizationId: tempLocalStorage('orgData.id')
|
||||
organizationId: tempLocalStorage("orgData.id"),
|
||||
});
|
||||
const newWorkspaceId = newWorkspace._id;
|
||||
|
||||
if (addAllUsers) {
|
||||
const orgUsers = await getOrganizationUsers({
|
||||
orgId: tempLocalStorage('orgData.id')
|
||||
orgId: tempLocalStorage("orgData.id"),
|
||||
});
|
||||
orgUsers.map(async (user: any) => {
|
||||
if (user.status == 'accepted') {
|
||||
if (user.status == "accepted") {
|
||||
const result = await addUserToWorkspace(
|
||||
user.user.email,
|
||||
newWorkspaceId
|
||||
);
|
||||
if (result?.invitee && result?.latestKey) {
|
||||
const PRIVATE_KEY = tempLocalStorage('PRIVATE_KEY');
|
||||
const PRIVATE_KEY = tempLocalStorage("PRIVATE_KEY");
|
||||
|
||||
// assymmetrically decrypt symmetric key with local private key
|
||||
const key = decryptAssymmetric({
|
||||
ciphertext: result.latestKey.encryptedKey,
|
||||
nonce: result.latestKey.nonce,
|
||||
publicKey: result.latestKey.sender.publicKey,
|
||||
privateKey: PRIVATE_KEY
|
||||
privateKey: PRIVATE_KEY,
|
||||
});
|
||||
|
||||
const { ciphertext, nonce } = encryptAssymmetric({
|
||||
plaintext: key,
|
||||
publicKey: result.invitee.publicKey,
|
||||
privateKey: PRIVATE_KEY
|
||||
privateKey: PRIVATE_KEY,
|
||||
}) as { ciphertext: string; nonce: string };
|
||||
|
||||
uploadKeys(
|
||||
@@ -116,11 +119,11 @@ export default function Layout({ children }: LayoutProps) {
|
||||
}
|
||||
});
|
||||
}
|
||||
router.push('/dashboard/' + newWorkspaceId + '?Development');
|
||||
router.push("/dashboard/" + newWorkspaceId + "?Development");
|
||||
setIsOpen(false);
|
||||
setNewWorkspaceName('');
|
||||
setNewWorkspaceName("");
|
||||
} else {
|
||||
console.error('A project with this name already exists.');
|
||||
console.error("A project with this name already exists.");
|
||||
setError(true);
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -131,62 +134,65 @@ export default function Layout({ children }: LayoutProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
href:
|
||||
'/dashboard/' +
|
||||
workspaceMapping[workspaceSelected as any] +
|
||||
'?Development',
|
||||
title: 'Secrets',
|
||||
emoji: <FontAwesomeIcon icon={faKey} />
|
||||
},
|
||||
{
|
||||
href: '/users/' + workspaceMapping[workspaceSelected as any],
|
||||
title: 'Members',
|
||||
emoji: <FontAwesomeIcon icon={faUser} />
|
||||
},
|
||||
{
|
||||
href: '/integrations/' + workspaceMapping[workspaceSelected as any],
|
||||
title: 'Integrations',
|
||||
emoji: <FontAwesomeIcon icon={faPlug} />
|
||||
},
|
||||
{
|
||||
href: '/settings/project/' + workspaceMapping[workspaceSelected as any],
|
||||
title: 'Project Settings',
|
||||
emoji: <FontAwesomeIcon icon={faGear} />
|
||||
}
|
||||
];
|
||||
const menuItems = useMemo(
|
||||
() => [
|
||||
{
|
||||
href:
|
||||
"/dashboard/" +
|
||||
workspaceMapping[workspaceSelected as any] +
|
||||
"?Development",
|
||||
title: t("nav:menu.secrets"),
|
||||
emoji: <FontAwesomeIcon icon={faKey} />,
|
||||
},
|
||||
{
|
||||
href: "/users/" + workspaceMapping[workspaceSelected as any],
|
||||
title: t("nav:menu.members"),
|
||||
emoji: <FontAwesomeIcon icon={faUser} />,
|
||||
},
|
||||
{
|
||||
href: "/integrations/" + workspaceMapping[workspaceSelected as any],
|
||||
title: t("nav:menu.integrations"),
|
||||
emoji: <FontAwesomeIcon icon={faPlug} />,
|
||||
},
|
||||
{
|
||||
href: "/settings/project/" + workspaceMapping[workspaceSelected as any],
|
||||
title: t("nav:menu.project-settings"),
|
||||
emoji: <FontAwesomeIcon icon={faGear} />,
|
||||
},
|
||||
],
|
||||
[t, workspaceMapping, workspaceSelected]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Put a user in a workspace if they're not in one yet
|
||||
const putUserInWorkSpace = async () => {
|
||||
if (tempLocalStorage('orgData.id') === '') {
|
||||
if (tempLocalStorage("orgData.id") === "") {
|
||||
const userOrgs = await getOrganizations();
|
||||
localStorage.setItem('orgData.id', userOrgs[0]._id);
|
||||
localStorage.setItem("orgData.id", userOrgs[0]._id);
|
||||
}
|
||||
|
||||
const orgUserProjects = await getOrganizationUserProjects({
|
||||
orgId: tempLocalStorage('orgData.id')
|
||||
orgId: tempLocalStorage("orgData.id"),
|
||||
});
|
||||
const userWorkspaces = orgUserProjects;
|
||||
if (
|
||||
userWorkspaces.length == 0 &&
|
||||
router.asPath != '/noprojects' &&
|
||||
!router.asPath.includes('settings')
|
||||
router.asPath != "/noprojects" &&
|
||||
!router.asPath.includes("settings")
|
||||
) {
|
||||
router.push('/noprojects');
|
||||
} else if (router.asPath != '/noprojects') {
|
||||
router.push("/noprojects");
|
||||
} else if (router.asPath != "/noprojects") {
|
||||
const intendedWorkspaceId = router.asPath
|
||||
.split('/')
|
||||
[router.asPath.split('/').length - 1].split('?')[0];
|
||||
.split("/")
|
||||
[router.asPath.split("/").length - 1].split("?")[0];
|
||||
// If a user is not a member of a workspace they are trying to access, just push them to one of theirs
|
||||
if (
|
||||
intendedWorkspaceId != 'heroku' &&
|
||||
intendedWorkspaceId != "heroku" &&
|
||||
!userWorkspaces
|
||||
.map((workspace: { _id: string }) => workspace._id)
|
||||
.includes(intendedWorkspaceId)
|
||||
) {
|
||||
router.push('/dashboard/' + userWorkspaces[0]._id + '?Development');
|
||||
router.push("/dashboard/" + userWorkspaces[0]._id + "?Development");
|
||||
} else {
|
||||
setWorkspaceList(
|
||||
userWorkspaces.map((workspace: any) => workspace.name)
|
||||
@@ -195,7 +201,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
Object.fromEntries(
|
||||
userWorkspaces.map((workspace: any) => [
|
||||
workspace.name,
|
||||
workspace._id
|
||||
workspace._id,
|
||||
])
|
||||
) as any
|
||||
);
|
||||
@@ -203,12 +209,12 @@ export default function Layout({ children }: LayoutProps) {
|
||||
Object.fromEntries(
|
||||
userWorkspaces.map((workspace: any) => [
|
||||
workspace._id,
|
||||
workspace.name
|
||||
workspace.name,
|
||||
])
|
||||
)[
|
||||
router.asPath
|
||||
.split('/')
|
||||
[router.asPath.split('/').length - 1].split('?')[0]
|
||||
.split("/")
|
||||
[router.asPath.split("/").length - 1].split("?")[0]
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -224,16 +230,16 @@ export default function Layout({ children }: LayoutProps) {
|
||||
workspaceMapping[workspaceSelected as any] &&
|
||||
`${workspaceMapping[workspaceSelected as any]}` !==
|
||||
router.asPath
|
||||
.split('/')
|
||||
[router.asPath.split('/').length - 1].split('?')[0]
|
||||
.split("/")
|
||||
[router.asPath.split("/").length - 1].split("?")[0]
|
||||
) {
|
||||
router.push(
|
||||
'/dashboard/' +
|
||||
"/dashboard/" +
|
||||
workspaceMapping[workspaceSelected as any] +
|
||||
'?Development'
|
||||
"?Development"
|
||||
);
|
||||
localStorage.setItem(
|
||||
'projectData.id',
|
||||
"projectData.id",
|
||||
`${workspaceMapping[workspaceSelected as any]}`
|
||||
);
|
||||
}
|
||||
@@ -257,7 +263,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
<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="text-gray-400 self-start ml-1 mb-1 text-xs font-semibold tracking-wide">
|
||||
PROJECT
|
||||
{t("nav:menu.project")}
|
||||
</div>
|
||||
{workspaceList.length > 0 ? (
|
||||
<Listbox
|
||||
@@ -282,11 +288,11 @@ export default function Layout({ children }: LayoutProps) {
|
||||
{workspaceList.length > 0 &&
|
||||
menuItems.map(({ href, title, emoji }) => (
|
||||
<li className="mt-0.5 mx-2" key={title}>
|
||||
{router.asPath.split('/')[1] === href.split('/')[1] &&
|
||||
(['project', 'billing', 'org', 'personal'].includes(
|
||||
router.asPath.split('/')[2]
|
||||
{router.asPath.split("/")[1] === href.split("/")[1] &&
|
||||
(["project", "billing", "org", "personal"].includes(
|
||||
router.asPath.split("/")[2]
|
||||
)
|
||||
? router.asPath.split('/')[2] === href.split('/')[2]
|
||||
? router.asPath.split("/")[2] === href.split("/")[2]
|
||||
: true) ? (
|
||||
<div
|
||||
className={`flex relative px-0.5 py-2.5 text-white text-sm rounded cursor-pointer bg-primary-50/10`}
|
||||
@@ -297,7 +303,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
</p>
|
||||
{title}
|
||||
</div>
|
||||
) : router.asPath == '/noprojects' ? (
|
||||
) : router.asPath == "/noprojects" ? (
|
||||
<div
|
||||
className={`flex p-2.5 text-white text-sm rounded`}
|
||||
>
|
||||
@@ -323,7 +329,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
</ul>
|
||||
</div>
|
||||
<div className="w-full mt-40 mb-4 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`}
|
||||
>
|
||||
@@ -334,12 +340,12 @@ export default function Layout({ children }: LayoutProps) {
|
||||
Infisical Guide
|
||||
<img
|
||||
src={`/images/progress-${
|
||||
totalOnboardingActionsDone == 0 ? '0' : ''
|
||||
}${totalOnboardingActionsDone == 1 ? '14' : ''}${
|
||||
totalOnboardingActionsDone == 2 ? '28' : ''
|
||||
}${totalOnboardingActionsDone == 3 ? '43' : ''}${
|
||||
totalOnboardingActionsDone == 4 ? '57' : ''
|
||||
}${totalOnboardingActionsDone == 5 ? '71' : ''}.svg`}
|
||||
totalOnboardingActionsDone == 0 ? "0" : ""
|
||||
}${totalOnboardingActionsDone == 1 ? "14" : ""}${
|
||||
totalOnboardingActionsDone == 2 ? "28" : ""
|
||||
}${totalOnboardingActionsDone == 3 ? "43" : ""}${
|
||||
totalOnboardingActionsDone == 4 ? "57" : ""
|
||||
}${totalOnboardingActionsDone == 5 ? "71" : ""}.svg`}
|
||||
height={58}
|
||||
width={58}
|
||||
alt="progress bar"
|
||||
@@ -359,12 +365,12 @@ export default function Layout({ children }: LayoutProps) {
|
||||
Infisical Guide
|
||||
<img
|
||||
src={`/images/progress-${
|
||||
totalOnboardingActionsDone == 0 ? '0' : ''
|
||||
}${totalOnboardingActionsDone == 1 ? '14' : ''}${
|
||||
totalOnboardingActionsDone == 2 ? '28' : ''
|
||||
}${totalOnboardingActionsDone == 3 ? '43' : ''}${
|
||||
totalOnboardingActionsDone == 4 ? '57' : ''
|
||||
}${totalOnboardingActionsDone == 5 ? '71' : ''}.svg`}
|
||||
totalOnboardingActionsDone == 0 ? "0" : ""
|
||||
}${totalOnboardingActionsDone == 1 ? "14" : ""}${
|
||||
totalOnboardingActionsDone == 2 ? "28" : ""
|
||||
}${totalOnboardingActionsDone == 3 ? "43" : ""}${
|
||||
totalOnboardingActionsDone == 4 ? "57" : ""
|
||||
}${totalOnboardingActionsDone == 5 ? "71" : ""}.svg`}
|
||||
height={58}
|
||||
width={58}
|
||||
alt="progress bar"
|
||||
@@ -394,9 +400,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
className="text-gray-300 text-7xl mb-8"
|
||||
/>
|
||||
<p className="text-gray-200 px-6 text-center text-lg max-w-sm">
|
||||
{' '}
|
||||
To use Infisical, please log in through a device with larger
|
||||
dimensions.{' '}
|
||||
{` ${t("common:no-mobile")} `}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
|
||||
import addIncidentContact from "~/pages/api/organization/addIncidentContact";
|
||||
@@ -14,6 +15,7 @@ const AddIncidentContactDialog = ({
|
||||
setIncidentContacts,
|
||||
}) => {
|
||||
let [incidentContactEmail, setIncidentContactEmail] = useState("");
|
||||
const { t } = useTranslation();
|
||||
|
||||
const submit = () => {
|
||||
setIncidentContacts(
|
||||
@@ -59,17 +61,16 @@ const AddIncidentContactDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400"
|
||||
>
|
||||
Add an Incident Contact
|
||||
{t("section-incident:add-dialog.title")}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
This contact will be notified in the unlikely event of a
|
||||
severe incident.
|
||||
{t("section-incident:add-dialog.description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="max-h-28">
|
||||
<InputField
|
||||
label="Email"
|
||||
label={t("common:email")}
|
||||
onChangeHandler={setIncidentContactEmail}
|
||||
type="varName"
|
||||
value={incidentContactEmail}
|
||||
@@ -81,7 +82,7 @@ const AddIncidentContactDialog = ({
|
||||
<Button
|
||||
onButtonPressed={submit}
|
||||
color="mineshaft"
|
||||
text="Add Incident Contact"
|
||||
text={t("section-incident:add-dialog.add-incident")}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Fragment, useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { Trans, useTranslation } from "next-i18next";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
|
||||
import Button from "../buttons/Button";
|
||||
@@ -15,6 +16,7 @@ const AddProjectMemberDialog = ({
|
||||
setEmail,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="z-50">
|
||||
@@ -49,48 +51,55 @@ const AddProjectMemberDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
Add a member to your project
|
||||
{t("section-members:add-dialog.add-member-to-project")}
|
||||
</Dialog.Title>
|
||||
) : (
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
All the users in your organization are already invited.
|
||||
{t("section-members:add-dialog.already-all-invited")}
|
||||
</Dialog.Title>
|
||||
)}
|
||||
<div className="mt-2 mb-4">
|
||||
{data?.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
The user will receive an email with the instructions.
|
||||
{t("section-members:add-dialog.user-will-email")}
|
||||
</p>
|
||||
<div className="">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex justify-center rounded-md py-1 text-sm text-gray-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={() =>
|
||||
router.push("/settings/org/" + router.query.id)
|
||||
}
|
||||
>
|
||||
If you are looking to add users to your org,
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="ml-1 inline-flex justify-center rounded-md py-1 text-sm text-gray-500 hover:text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={() =>
|
||||
router.push(
|
||||
"/settings/org/" + router.query.id + "?invite"
|
||||
)
|
||||
}
|
||||
>
|
||||
click here.
|
||||
</button>
|
||||
<Trans
|
||||
i18nKey="section-members:add-dialog.looking-add"
|
||||
components={[
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex justify-center rounded-md py-1 text-sm text-gray-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={() =>
|
||||
router.push(
|
||||
"/settings/org/" + router.query.id
|
||||
)
|
||||
}
|
||||
/>,
|
||||
// eslint-disable-next-line react/jsx-key
|
||||
<button
|
||||
type="button"
|
||||
className="ml-1 inline-flex justify-center rounded-md py-1 text-sm text-gray-500 hover:text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={() =>
|
||||
router.push(
|
||||
"/settings/org/" +
|
||||
router.query.id +
|
||||
"?invite"
|
||||
)
|
||||
}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500">
|
||||
Add more users to the organization first.
|
||||
{t("section-members:add-dialog.add-user-org-first")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -110,7 +119,7 @@ const AddProjectMemberDialog = ({
|
||||
<Button
|
||||
onButtonPressed={submitModal}
|
||||
color="mineshaft"
|
||||
text="Add Member"
|
||||
text={t("section-members:add-member")}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
@@ -120,7 +129,7 @@ const AddProjectMemberDialog = ({
|
||||
router.push("/settings/org/" + router.query.id)
|
||||
}
|
||||
color="mineshaft"
|
||||
text="Add Users to Organization"
|
||||
text={t("section-members:add-dialog.add-user-to-org")}
|
||||
size="md"
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,40 +1,42 @@
|
||||
import { Fragment, useState } from 'react';
|
||||
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Dialog, Transition } from '@headlessui/react';
|
||||
import nacl from 'tweetnacl';
|
||||
import { Fragment, useState } from "react";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import nacl from "tweetnacl";
|
||||
|
||||
import addServiceToken from '~/pages/api/serviceToken/addServiceToken';
|
||||
import getLatestFileKey from '~/pages/api/workspace/getLatestFileKey';
|
||||
import addServiceToken from "~/pages/api/serviceToken/addServiceToken";
|
||||
import getLatestFileKey from "~/pages/api/workspace/getLatestFileKey";
|
||||
|
||||
import { envMapping } from '../../../public/data/frequentConstants';
|
||||
import { envMapping } from "../../../public/data/frequentConstants";
|
||||
import {
|
||||
decryptAssymmetric,
|
||||
encryptAssymmetric
|
||||
} from '../../utilities/cryptography/crypto';
|
||||
import Button from '../buttons/Button';
|
||||
import InputField from '../InputField';
|
||||
import ListBox from '../Listbox';
|
||||
encryptAssymmetric,
|
||||
} from "../../utilities/cryptography/crypto";
|
||||
import Button from "../buttons/Button";
|
||||
import InputField from "../InputField";
|
||||
import ListBox from "../Listbox";
|
||||
|
||||
const expiryMapping = {
|
||||
'1 day': 86400,
|
||||
'7 days': 604800,
|
||||
'1 month': 2592000,
|
||||
'6 months': 15552000,
|
||||
'12 months': 31104000
|
||||
"1 day": 86400,
|
||||
"7 days": 604800,
|
||||
"1 month": 2592000,
|
||||
"6 months": 15552000,
|
||||
"12 months": 31104000,
|
||||
};
|
||||
|
||||
const AddServiceTokenDialog = ({
|
||||
isOpen,
|
||||
closeModal,
|
||||
workspaceId,
|
||||
workspaceName
|
||||
workspaceName,
|
||||
}) => {
|
||||
const [serviceToken, setServiceToken] = useState('');
|
||||
const [serviceTokenName, setServiceTokenName] = useState('');
|
||||
const [serviceTokenEnv, setServiceTokenEnv] = useState('Development');
|
||||
const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState('1 day');
|
||||
const [serviceToken, setServiceToken] = useState("");
|
||||
const [serviceTokenName, setServiceTokenName] = useState("");
|
||||
const [serviceTokenEnv, setServiceTokenEnv] = useState("Development");
|
||||
const [serviceTokenExpiresIn, setServiceTokenExpiresIn] = useState("1 day");
|
||||
const [serviceTokenCopied, setServiceTokenCopied] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const generateServiceToken = async () => {
|
||||
const latestFileKey = await getLatestFileKey({ workspaceId });
|
||||
@@ -43,7 +45,7 @@ const AddServiceTokenDialog = ({
|
||||
ciphertext: latestFileKey.latestKey.encryptedKey,
|
||||
nonce: latestFileKey.latestKey.nonce,
|
||||
publicKey: latestFileKey.latestKey.sender.publicKey,
|
||||
privateKey: localStorage.getItem('PRIVATE_KEY')
|
||||
privateKey: localStorage.getItem("PRIVATE_KEY"),
|
||||
});
|
||||
|
||||
// generate new public/private key pair
|
||||
@@ -55,7 +57,7 @@ const AddServiceTokenDialog = ({
|
||||
const { ciphertext: encryptedKey, nonce } = encryptAssymmetric({
|
||||
plaintext: key,
|
||||
publicKey,
|
||||
privateKey
|
||||
privateKey,
|
||||
});
|
||||
|
||||
let newServiceToken = await addServiceToken({
|
||||
@@ -65,16 +67,16 @@ const AddServiceTokenDialog = ({
|
||||
expiresIn: expiryMapping[serviceTokenExpiresIn],
|
||||
publicKey,
|
||||
encryptedKey,
|
||||
nonce
|
||||
nonce,
|
||||
});
|
||||
|
||||
const serviceToken = newServiceToken + ',' + privateKey;
|
||||
const serviceToken = newServiceToken + "," + privateKey;
|
||||
setServiceToken(serviceToken);
|
||||
};
|
||||
|
||||
function copyToClipboard() {
|
||||
// Get the text field
|
||||
var copyText = document.getElementById('serviceToken');
|
||||
var copyText = document.getElementById("serviceToken");
|
||||
|
||||
// Select the text field
|
||||
copyText.select();
|
||||
@@ -91,8 +93,8 @@ const AddServiceTokenDialog = ({
|
||||
|
||||
const closeAddServiceTokenModal = () => {
|
||||
closeModal();
|
||||
setServiceTokenName('');
|
||||
setServiceToken('');
|
||||
setServiceTokenName("");
|
||||
setServiceToken("");
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -122,27 +124,26 @@ const AddServiceTokenDialog = ({
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
{serviceToken == '' ? (
|
||||
{serviceToken == "" ? (
|
||||
<Dialog.Panel className="w-full max-w-md transform rounded-md bg-bunker-800 border border-gray-700 p-6 text-left align-middle shadow-xl transition-all">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
Add a service token for {workspaceName}
|
||||
{t("section-token:add-dialog.title", {
|
||||
target: workspaceName,
|
||||
})}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
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.
|
||||
{t("section-token:add-dialog.description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-h-28 mb-2">
|
||||
<InputField
|
||||
label="Service Token Name"
|
||||
label={t("section-token:add-dialog.name")}
|
||||
onChangeHandler={setServiceTokenName}
|
||||
type="varName"
|
||||
value={serviceTokenName}
|
||||
@@ -155,13 +156,13 @@ const AddServiceTokenDialog = ({
|
||||
selected={serviceTokenEnv}
|
||||
onChange={setServiceTokenEnv}
|
||||
data={[
|
||||
'Development',
|
||||
'Staging',
|
||||
'Production',
|
||||
'Testing'
|
||||
"Development",
|
||||
"Staging",
|
||||
"Production",
|
||||
"Testing",
|
||||
]}
|
||||
isFull={true}
|
||||
text="Environment: "
|
||||
width="full"
|
||||
text={`${t("common:environment")}: `}
|
||||
/>
|
||||
</div>
|
||||
<div className="max-h-28">
|
||||
@@ -169,14 +170,14 @@ const AddServiceTokenDialog = ({
|
||||
selected={serviceTokenExpiresIn}
|
||||
onChange={setServiceTokenExpiresIn}
|
||||
data={[
|
||||
'1 day',
|
||||
'7 days',
|
||||
'1 month',
|
||||
'6 months',
|
||||
'12 months'
|
||||
"1 day",
|
||||
"7 days",
|
||||
"1 month",
|
||||
"6 months",
|
||||
"12 months",
|
||||
]}
|
||||
isFull={true}
|
||||
text="Expires in: "
|
||||
width="full"
|
||||
text={`${t("common:expired-in")}: `}
|
||||
/>
|
||||
</div>
|
||||
<div className="max-w-max">
|
||||
@@ -184,10 +185,10 @@ const AddServiceTokenDialog = ({
|
||||
<Button
|
||||
onButtonPressed={() => generateServiceToken()}
|
||||
color="mineshaft"
|
||||
text="Add Service Token"
|
||||
textDisabled="Add Service Token"
|
||||
text={t("section-token:add-dialog.add")}
|
||||
textDisabled={t("section-token:add-dialog.add")}
|
||||
size="md"
|
||||
active={serviceTokenName == '' ? false : true}
|
||||
active={serviceTokenName == "" ? false : true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,13 +199,14 @@ const AddServiceTokenDialog = ({
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-400 z-50"
|
||||
>
|
||||
Copy your service token
|
||||
{t("section-token:add-dialog.copy-service-token")}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 mb-4">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-sm text-gray-500">
|
||||
Once you close this popup, you will never see your
|
||||
service token again
|
||||
{t(
|
||||
"section-token:add-dialog.copy-service-token-description"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -234,7 +236,7 @@ const AddServiceTokenDialog = ({
|
||||
)}
|
||||
</button>
|
||||
<span className="absolute hidden group-hover:flex group-hover:animate-popup duration-300 w-28 -left-8 -top-20 translate-y-full px-3 py-2 bg-chicago-900 rounded-md text-center text-gray-400 text-sm">
|
||||
Click to Copy
|
||||
{t("common.click-to-copy")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { type ChangeEvent, type DragEvent, useState } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { faUpload } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { type ChangeEvent, type DragEvent, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faUpload } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Button from '../basic/buttons/Button';
|
||||
import Error from '../basic/Error';
|
||||
import parse from '../utilities/file';
|
||||
import guidGenerator from '../utilities/randomId';
|
||||
import Button from "../basic/buttons/Button";
|
||||
import Error from "../basic/Error";
|
||||
import parse from "../utilities/file";
|
||||
import guidGenerator from "../utilities/randomId";
|
||||
|
||||
interface DropZoneProps {
|
||||
// TODO: change Data type from any
|
||||
@@ -26,8 +27,10 @@ const DropZone = ({
|
||||
errorDragAndDrop,
|
||||
setButtonReady,
|
||||
keysExist,
|
||||
numCurrentRows
|
||||
numCurrentRows,
|
||||
}: DropZoneProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleDragEnter = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -43,7 +46,7 @@ const DropZone = ({
|
||||
e.stopPropagation();
|
||||
|
||||
// set dropEffect to copy i.e copy of the source item
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
e.dataTransfer.dropEffect = "copy";
|
||||
};
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -54,7 +57,7 @@ const DropZone = ({
|
||||
setTimeout(() => setLoading(false), 5000);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
e.dataTransfer.dropEffect = "copy";
|
||||
|
||||
const file = e.dataTransfer.files[0];
|
||||
const reader = new FileReader();
|
||||
@@ -69,7 +72,7 @@ const DropZone = ({
|
||||
pos: numCurrentRows + index,
|
||||
key: key,
|
||||
value: keyPairs[key as keyof typeof keyPairs],
|
||||
type: 'shared'
|
||||
type: "shared",
|
||||
};
|
||||
});
|
||||
setData(newData);
|
||||
@@ -96,16 +99,16 @@ const DropZone = ({
|
||||
reader.onload = (event) => {
|
||||
if (event.target === null || event.target.result === null) return;
|
||||
const { result } = event.target;
|
||||
if (typeof result === 'string') {
|
||||
if (typeof result === "string") {
|
||||
const newData = result
|
||||
.split('\n')
|
||||
.split("\n")
|
||||
.map((line: string, index: number) => {
|
||||
return {
|
||||
id: guidGenerator(),
|
||||
pos: numCurrentRows + index,
|
||||
key: line.split('=')[0],
|
||||
value: line.split('=').slice(1, line.split('=').length).join('='),
|
||||
type: 'shared'
|
||||
key: line.split("=")[0],
|
||||
value: line.split("=").slice(1, line.split("=").length).join("="),
|
||||
type: "shared",
|
||||
};
|
||||
});
|
||||
setData(newData);
|
||||
@@ -149,9 +152,7 @@ const DropZone = ({
|
||||
icon={faUpload}
|
||||
className="text-bunker-300 text-3xl mr-6"
|
||||
/>
|
||||
<p className="text-bunker-300 mt-1">
|
||||
Drag and drop your .env file here to add more keys.
|
||||
</p>
|
||||
<p className="text-bunker-300 mt-1">{t("common:drop-zone-keys")}</p>
|
||||
</div>
|
||||
{errorDragAndDrop ? (
|
||||
<div className="mt-8 max-w-xl opacity-80">
|
||||
@@ -170,7 +171,7 @@ const DropZone = ({
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<FontAwesomeIcon icon={faUpload} className="text-7xl mb-8" />
|
||||
<p className="">Drag and drop your .env file here.</p>
|
||||
<p className="">{t("common:drop-zone")}</p>
|
||||
<input
|
||||
id="fileSelect"
|
||||
type="file"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable react/jsx-key */
|
||||
import { Fragment, useEffect, useState } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import { faGithub, faSlack } from '@fortawesome/free-brands-svg-icons';
|
||||
import { faCircleQuestion } from '@fortawesome/free-regular-svg-icons';
|
||||
import { Fragment, useEffect, useMemo, useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { TFunction, useTranslation } from "next-i18next";
|
||||
import { faGithub, faSlack } from "@fortawesome/free-brands-svg-icons";
|
||||
import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons";
|
||||
import {
|
||||
faAngleDown,
|
||||
faBook,
|
||||
@@ -12,39 +12,39 @@ import {
|
||||
faEnvelope,
|
||||
faGear,
|
||||
faPlus,
|
||||
faRightFromBracket
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Menu, Transition } from '@headlessui/react';
|
||||
faRightFromBracket,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Menu, Transition } from "@headlessui/react";
|
||||
|
||||
import logout from '~/pages/api/auth/Logout';
|
||||
import getOrganization from '~/pages/api/organization/GetOrg';
|
||||
import getOrganizations from '~/pages/api/organization/getOrgs';
|
||||
import getUser from '~/pages/api/user/getUser';
|
||||
import logout from "~/pages/api/auth/Logout";
|
||||
|
||||
import guidGenerator from '../utilities/randomId';
|
||||
import getOrganization from "../../pages/api/organization/GetOrg";
|
||||
import getOrganizations from "../../pages/api/organization/getOrgs";
|
||||
import getUser from "../../pages/api/user/getUser";
|
||||
import guidGenerator from "../utilities/randomId";
|
||||
|
||||
const supportOptions = [
|
||||
const supportOptions = (t: TFunction) => [
|
||||
[
|
||||
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faSlack} />,
|
||||
'Join Slack Forum',
|
||||
'https://join.slack.com/t/infisical-users/shared_invite/zt-1kdbk07ro-RtoyEt_9E~fyzGo_xQYP6g'
|
||||
t("nav:support.slack"),
|
||||
"https://join.slack.com/t/infisical/shared_invite/zt-1dgg63ln8-G7PCNJdCymAT9YF3j1ewVA",
|
||||
],
|
||||
[
|
||||
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faBook} />,
|
||||
'Read Docs',
|
||||
'https://infisical.com/docs/getting-started/introduction'
|
||||
t("nav:support.docs"),
|
||||
"https://infisical.com/docs/getting-started/introduction",
|
||||
],
|
||||
[
|
||||
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faGithub} />,
|
||||
'Open a GitHub Issue',
|
||||
'https://github.com/Infisical/infisical-cli/issues'
|
||||
t("nav:support.issue"),
|
||||
"https://github.com/Infisical/infisical-cli/issues",
|
||||
],
|
||||
[
|
||||
<FontAwesomeIcon className="text-lg pl-1.5 pr-3" icon={faEnvelope} />,
|
||||
'Send us an Email',
|
||||
'mailto:support@infisical.com'
|
||||
]
|
||||
t("nav:support.email"),
|
||||
"mailto:support@infisical.com",
|
||||
],
|
||||
];
|
||||
|
||||
export interface ICurrentOrg {
|
||||
@@ -68,6 +68,10 @@ export default function Navbar() {
|
||||
const [orgs, setOrgs] = useState([]);
|
||||
const [currentOrg, setCurrentOrg] = useState<ICurrentOrg | undefined>();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const supportOptionsList = useMemo(() => supportOptions(t), [t]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const userData = await getUser();
|
||||
@@ -75,16 +79,16 @@ export default function Navbar() {
|
||||
const orgsData = await getOrganizations();
|
||||
setOrgs(orgsData);
|
||||
const currentOrg = await getOrganization({
|
||||
orgId: String(localStorage.getItem('orgData.id'))
|
||||
orgId: String(localStorage.getItem("orgData.id")),
|
||||
});
|
||||
setCurrentOrg(currentOrg);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const closeApp = async () => {
|
||||
console.log('Logging out...');
|
||||
console.log("Logging out...");
|
||||
await logout();
|
||||
router.push('/login');
|
||||
router.push("/login");
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -119,18 +123,17 @@ export default function Navbar() {
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="absolute right-0 mt-0.5 w-64 origin-top-right rounded-md bg-bunker border border-mineshaft-700 shadow-lg ring-1 ring-black z-20 ring-opacity-5 focus:outline-none px-2 py-1.5">
|
||||
{supportOptions.map((option) => (
|
||||
// eslint-disable-next-line react/jsx-no-target-blank
|
||||
{supportOptionsList.map(([icon, text, url]) => (
|
||||
<a
|
||||
key={guidGenerator()}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
href={String(option[2])}
|
||||
rel="noopener noreferrer"
|
||||
href={String(url)}
|
||||
className="font-normal text-gray-300 duration-200 rounded-md w-full flex items-center py-0.5"
|
||||
>
|
||||
<div className="relative flex justify-start items-center cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/10 duration-200 hover:text-gray-200 w-full">
|
||||
{option[0]}
|
||||
<div className="text-sm">{option[1]}</div>
|
||||
{icon}
|
||||
<div className="text-sm">{text}</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
@@ -159,11 +162,11 @@ export default function Navbar() {
|
||||
<Menu.Items className="absolute right-0 mt-0.5 w-64 origin-top-right divide-y divide-gray-700 rounded-md bg-bunker border border-mineshaft-700 shadow-lg ring-1 ring-black z-20 ring-opacity-5 focus:outline-none">
|
||||
<div className="px-1 py-1 ">
|
||||
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
|
||||
SIGNED IN AS
|
||||
{t("nav:user.signed-in-as")}
|
||||
</div>
|
||||
<div
|
||||
onClick={() =>
|
||||
router.push('/settings/personal/' + router.query.id)
|
||||
router.push("/settings/personal/" + router.query.id)
|
||||
}
|
||||
className="flex flex-row items-center px-1 mx-1 my-1 hover:bg-white/5 cursor-pointer rounded-md"
|
||||
>
|
||||
@@ -173,11 +176,11 @@ export default function Navbar() {
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div>
|
||||
<p className="text-gray-300 px-2 pt-1 text-sm">
|
||||
{' '}
|
||||
{" "}
|
||||
{user?.firstName} {user?.lastName}
|
||||
</p>
|
||||
<p className="text-gray-400 px-2 pb-1 text-xs">
|
||||
{' '}
|
||||
{" "}
|
||||
{user?.email}
|
||||
</p>
|
||||
</div>
|
||||
@@ -190,11 +193,11 @@ export default function Navbar() {
|
||||
</div>
|
||||
<div className="px-2 pt-2">
|
||||
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
|
||||
CURRENT ORGANIZATION
|
||||
{t("nav:user.current-organization")}
|
||||
</div>
|
||||
<div
|
||||
onClick={() =>
|
||||
router.push('/settings/org/' + router.query.id)
|
||||
router.push("/settings/org/" + router.query.id)
|
||||
}
|
||||
className="flex flex-row items-center px-2 mt-2 py-1 hover:bg-white/5 cursor-pointer rounded-md"
|
||||
>
|
||||
@@ -217,7 +220,7 @@ export default function Navbar() {
|
||||
>
|
||||
<div
|
||||
onClick={() =>
|
||||
router.push('/settings/billing/' + router.query.id)
|
||||
router.push("/settings/billing/" + router.query.id)
|
||||
}
|
||||
className="mt-1 relative flex justify-start cursor-pointer select-none py-2 px-2 rounded-md text-gray-400 hover:bg-white/5 duration-200 hover:text-gray-200"
|
||||
>
|
||||
@@ -225,7 +228,7 @@ export default function Navbar() {
|
||||
className="text-lg pl-1.5 pr-3"
|
||||
icon={faCoins}
|
||||
/>
|
||||
<div className="text-sm">Usage & Billing</div>
|
||||
<div className="text-sm">{t("nav:user.usage-billing")}</div>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
@@ -235,7 +238,7 @@ export default function Navbar() {
|
||||
<div
|
||||
onClick={() =>
|
||||
router.push(
|
||||
'/settings/org/' + router.query.id + '?invite'
|
||||
"/settings/org/" + router.query.id + "?invite"
|
||||
)
|
||||
}
|
||||
className="relative flex justify-start cursor-pointer select-none py-2 pl-10 pr-4 rounded-md text-gray-400 hover:bg-primary/100 duration-200 hover:text-black hover:font-semibold mt-1"
|
||||
@@ -243,26 +246,26 @@ export default function Navbar() {
|
||||
<span className="rounded-lg absolute inset-y-0 left-0 flex items-center pl-3 pr-4">
|
||||
<FontAwesomeIcon icon={faPlus} className="ml-1" />
|
||||
</span>
|
||||
<div className="text-sm ml-1">Invite Members</div>
|
||||
<div className="text-sm ml-1">{t("nav:user.invite")}</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{orgs?.length > 1 && (
|
||||
<div className="px-1 pt-1">
|
||||
<div className="text-gray-400 self-start ml-2 mt-2 text-xs font-semibold tracking-wide">
|
||||
OTHER ORGANIZATIONS
|
||||
{t("nav:user.other-organizations")}
|
||||
</div>
|
||||
<div className="flex flex-col items-start px-1 mt-3 mb-2">
|
||||
{orgs
|
||||
.filter(
|
||||
(org: { _id: string }) =>
|
||||
org._id != localStorage.getItem('orgData.id')
|
||||
org._id != localStorage.getItem("orgData.id")
|
||||
)
|
||||
.map((org: { _id: string; name: string }) => (
|
||||
<div
|
||||
key={guidGenerator()}
|
||||
onClick={() => {
|
||||
localStorage.setItem('orgData.id', org._id);
|
||||
localStorage.setItem("orgData.id", org._id);
|
||||
router.reload();
|
||||
}}
|
||||
className="flex flex-row justify-start items-center hover:bg-white/5 w-full p-1.5 cursor-pointer rounded-md"
|
||||
@@ -287,8 +290,8 @@ export default function Navbar() {
|
||||
onClick={closeApp}
|
||||
className={`${
|
||||
active
|
||||
? 'bg-red font-semibold text-white'
|
||||
: 'text-gray-400'
|
||||
? "bg-red font-semibold text-white"
|
||||
: "text-gray-400"
|
||||
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
|
||||
>
|
||||
<div className="relative flex justify-start items-center cursor-pointer select-none">
|
||||
@@ -296,7 +299,7 @@ export default function Navbar() {
|
||||
className="text-lg ml-1.5 mr-3"
|
||||
icon={faRightFromBracket}
|
||||
/>
|
||||
Log Out
|
||||
{t("common:logout")}
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
|
||||
52
frontend/components/utilities/withTranslateProps.ts
Normal file
52
frontend/components/utilities/withTranslateProps.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { GetServerSideProps, GetStaticProps } from "next";
|
||||
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
|
||||
|
||||
const DefaultNamespaces = ["common", "nav"];
|
||||
|
||||
type GetTranslatedStaticProps = (
|
||||
namespaces: string[],
|
||||
getStaticProps?: GetStaticProps<any>
|
||||
) => GetStaticProps;
|
||||
|
||||
type GetTranslatedServerSideProps = (
|
||||
namespaces: string[],
|
||||
getStaticProps?: GetServerSideProps<any>
|
||||
) => GetServerSideProps;
|
||||
|
||||
export const getTranslatedStaticProps: GetTranslatedStaticProps =
|
||||
(namespaces, getStaticProps) =>
|
||||
async ({ locale, ...context }) => {
|
||||
let staticProps = { props: {} };
|
||||
if (typeof getStaticProps === "function") {
|
||||
staticProps = (await getStaticProps(context)) as any;
|
||||
}
|
||||
return {
|
||||
...staticProps,
|
||||
props: {
|
||||
...(await serverSideTranslations(locale ?? "en", [
|
||||
...DefaultNamespaces,
|
||||
...namespaces,
|
||||
])),
|
||||
...staticProps.props,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getTranslatedServerSideProps: GetTranslatedServerSideProps =
|
||||
(namespaces, getServerSideProps) =>
|
||||
async ({ locale, ...context }) => {
|
||||
let staticProps = { props: {} };
|
||||
if (typeof getServerSideProps === "function") {
|
||||
staticProps = (await getServerSideProps(context)) as any;
|
||||
}
|
||||
return {
|
||||
...staticProps,
|
||||
props: {
|
||||
...(await serverSideTranslations(locale ?? "en", [
|
||||
...DefaultNamespaces,
|
||||
...namespaces,
|
||||
])),
|
||||
...staticProps.props,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -16,3 +16,8 @@ export const publicPaths = [
|
||||
`/terms`,
|
||||
`/subprocessors`,
|
||||
];
|
||||
|
||||
export const languageMap = {
|
||||
en: "English",
|
||||
ko: "한국어",
|
||||
};
|
||||
|
||||
26
frontend/next-i18next.config.js
Normal file
26
frontend/next-i18next.config.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @type {import('next-i18next').UserConfig}
|
||||
*/
|
||||
module.exports = {
|
||||
// https://www.i18next.com/overview/configuration-options#logging
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
i18n: {
|
||||
defaultLocale: "en",
|
||||
locales: ["en", "ko"],
|
||||
},
|
||||
fallbackLng: {
|
||||
default: ["en"],
|
||||
},
|
||||
|
||||
reloadOnPrerender: process.env.NODE_ENV === "development",
|
||||
|
||||
/**
|
||||
* @link https://github.com/i18next/next-i18next#6-advanced-configuration
|
||||
*/
|
||||
// saveMissing: false,
|
||||
// strictMode: true,
|
||||
// serializeConfig: false,
|
||||
// react: { useSuspense: false }
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
// next.config.js
|
||||
const { i18n } = require("./next-i18next.config.js");
|
||||
|
||||
const ContentSecurityPolicy = `
|
||||
default-src 'self';
|
||||
@@ -60,4 +60,8 @@ module.exports = {
|
||||
},
|
||||
];
|
||||
},
|
||||
webpack: (config, { isServer, webpack }) => {
|
||||
return config;
|
||||
},
|
||||
i18n,
|
||||
};
|
||||
|
||||
555
frontend/package-lock.json
generated
555
frontend/package-lock.json
generated
@@ -24,10 +24,12 @@
|
||||
"fs": "^0.0.1-security",
|
||||
"gray-matter": "^4.0.3",
|
||||
"http-proxy": "^1.18.1",
|
||||
"i18next": "^22.4.6",
|
||||
"jspdf": "^2.5.1",
|
||||
"jsrp": "^0.2.4",
|
||||
"markdown-it": "^13.0.1",
|
||||
"next": "^12.2.5",
|
||||
"next-i18next": "^13.0.2",
|
||||
"posthog-js": "^1.34.0",
|
||||
"query-string": "^7.1.3",
|
||||
"react": "^17.0.2",
|
||||
@@ -36,6 +38,7 @@
|
||||
"react-dom": "^17.0.2",
|
||||
"react-github-btn": "^1.4.0",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-i18next": "^12.1.1",
|
||||
"react-mailchimp-subscribe": "^2.1.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-redux": "^8.0.2",
|
||||
@@ -393,11 +396,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
|
||||
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
|
||||
"version": "7.20.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
|
||||
"integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1368,14 +1371,14 @@
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
|
||||
"integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==",
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.1.tgz",
|
||||
"integrity": "sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "5.45.0",
|
||||
"@typescript-eslint/type-utils": "5.45.0",
|
||||
"@typescript-eslint/utils": "5.45.0",
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/type-utils": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -1400,6 +1403,53 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
|
||||
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@@ -1491,13 +1541,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz",
|
||||
"integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==",
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.1.tgz",
|
||||
"integrity": "sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "5.45.0",
|
||||
"@typescript-eslint/utils": "5.45.0",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
@@ -1517,6 +1567,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
|
||||
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@@ -1604,16 +1711,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz",
|
||||
"integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==",
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.1.tgz",
|
||||
"integrity": "sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.45.0",
|
||||
"@typescript-eslint/types": "5.45.0",
|
||||
"@typescript-eslint/typescript-estree": "5.45.0",
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
@@ -1629,6 +1736,97 @@
|
||||
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
|
||||
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
|
||||
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
@@ -1651,6 +1849,12 @@
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.45.0.tgz",
|
||||
@@ -2401,7 +2605,6 @@
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz",
|
||||
"integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
@@ -4051,6 +4254,14 @@
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"dependencies": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-tokenize": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz",
|
||||
@@ -4113,6 +4324,33 @@
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "22.4.6",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.6.tgz",
|
||||
"integrity": "sha512-9Tm1ezxWyzV+306CIDMBbYBitC1jedQyYuuLtIv7oxjp2ohh8eyxP9xytIf+2bbQfhH784IQKPSYp+Zq9+YSbw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com/i18next.html"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6"
|
||||
}
|
||||
},
|
||||
"node_modules/i18next-fs-backend": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz",
|
||||
"integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA=="
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -5500,6 +5738,45 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next-i18next": {
|
||||
"version": "13.0.2",
|
||||
"resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.0.2.tgz",
|
||||
"integrity": "sha512-aUHyKT2kztMgEP44zDB5KoW8XZUQawIdOYWXcrMH6lxAcS0kBsKX0uKMzGS5XlgLW88gvOVc3D7NdfCznLgyyg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com/i18next.html"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://locize.com"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/belgattitude"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"core-js": "^3",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"i18next-fs-backend": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": "^22.0.6",
|
||||
"next": ">= 12.0.0",
|
||||
"react": ">= 17.0.2",
|
||||
"react-i18next": "^12.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.30.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.30.0.tgz",
|
||||
@@ -6295,6 +6572,27 @@
|
||||
"react-dom": ">= 16.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
"version": "12.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
|
||||
"integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.14.5",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": ">= 19.0.0",
|
||||
"react": ">= 16.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@@ -7666,6 +7964,14 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@@ -7986,11 +8292,11 @@
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.18.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
|
||||
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
|
||||
"version": "7.20.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
|
||||
"integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
}
|
||||
},
|
||||
"@babel/runtime-corejs3": {
|
||||
@@ -8690,14 +8996,14 @@
|
||||
"integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz",
|
||||
"integrity": "sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==",
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.1.tgz",
|
||||
"integrity": "sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "5.45.0",
|
||||
"@typescript-eslint/type-utils": "5.45.0",
|
||||
"@typescript-eslint/utils": "5.45.0",
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/type-utils": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"ignore": "^5.2.0",
|
||||
"natural-compare-lite": "^1.4.0",
|
||||
@@ -8706,6 +9012,32 @@
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
|
||||
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@@ -8763,17 +9095,48 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.45.0.tgz",
|
||||
"integrity": "sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==",
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.1.tgz",
|
||||
"integrity": "sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "5.45.0",
|
||||
"@typescript-eslint/utils": "5.45.0",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"@typescript-eslint/utils": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"tsutils": "^3.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
|
||||
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
@@ -8830,21 +9193,71 @@
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.45.0.tgz",
|
||||
"integrity": "sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==",
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.1.tgz",
|
||||
"integrity": "sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@types/semver": "^7.3.12",
|
||||
"@typescript-eslint/scope-manager": "5.45.0",
|
||||
"@typescript-eslint/types": "5.45.0",
|
||||
"@typescript-eslint/typescript-estree": "5.45.0",
|
||||
"@typescript-eslint/scope-manager": "5.47.1",
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/typescript-estree": "5.47.1",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"semver": "^7.3.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.1.tgz",
|
||||
"integrity": "sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.1.tgz",
|
||||
"integrity": "sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.1.tgz",
|
||||
"integrity": "sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"@typescript-eslint/visitor-keys": "5.47.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.7",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.47.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.1.tgz",
|
||||
"integrity": "sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.47.1",
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
@@ -8860,6 +9273,12 @@
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9400,8 +9819,7 @@
|
||||
"core-js": {
|
||||
"version": "3.26.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.26.0.tgz",
|
||||
"integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==",
|
||||
"optional": true
|
||||
"integrity": "sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw=="
|
||||
},
|
||||
"core-js-pure": {
|
||||
"version": "3.26.1",
|
||||
@@ -10644,6 +11062,14 @@
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"requires": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"html-tokenize": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz",
|
||||
@@ -10699,6 +11125,19 @@
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"i18next": {
|
||||
"version": "22.4.6",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.6.tgz",
|
||||
"integrity": "sha512-9Tm1ezxWyzV+306CIDMBbYBitC1jedQyYuuLtIv7oxjp2ohh8eyxP9xytIf+2bbQfhH784IQKPSYp+Zq9+YSbw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.20.6"
|
||||
}
|
||||
},
|
||||
"i18next-fs-backend": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz",
|
||||
"integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA=="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -11600,6 +12039,18 @@
|
||||
"use-sync-external-store": "1.2.0"
|
||||
}
|
||||
},
|
||||
"next-i18next": {
|
||||
"version": "13.0.2",
|
||||
"resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.0.2.tgz",
|
||||
"integrity": "sha512-aUHyKT2kztMgEP44zDB5KoW8XZUQawIdOYWXcrMH6lxAcS0kBsKX0uKMzGS5XlgLW88gvOVc3D7NdfCznLgyyg==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"core-js": "^3",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"i18next-fs-backend": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node-abi": {
|
||||
"version": "3.30.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.30.0.tgz",
|
||||
@@ -12156,6 +12607,15 @@
|
||||
"react-resizable": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"react-i18next": {
|
||||
"version": "12.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.1.1.tgz",
|
||||
"integrity": "sha512-mFdieOI0LDy84q3JuZU6Aou1DoWW2fhapcTGeBS8+vWSJuViuoCLQAMYSb0QoHhXS8B0WKUOPpx4cffAP7r/aA==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.14.5",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@@ -13126,6 +13586,11 @@
|
||||
"unist-util-stringify-position": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
"fs": "^0.0.1-security",
|
||||
"gray-matter": "^4.0.3",
|
||||
"http-proxy": "^1.18.1",
|
||||
"i18next": "^22.4.6",
|
||||
"jspdf": "^2.5.1",
|
||||
"jsrp": "^0.2.4",
|
||||
"markdown-it": "^13.0.1",
|
||||
"next": "^12.2.5",
|
||||
"next-i18next": "^13.0.2",
|
||||
"posthog-js": "^1.34.0",
|
||||
"query-string": "^7.1.3",
|
||||
"react": "^17.0.2",
|
||||
@@ -40,6 +42,7 @@
|
||||
"react-dom": "^17.0.2",
|
||||
"react-github-btn": "^1.4.0",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-i18next": "^12.1.1",
|
||||
"react-mailchimp-subscribe": "^2.1.3",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-redux": "^8.0.2",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { appWithTranslation } from "next-i18next";
|
||||
import { config } from "@fortawesome/fontawesome-svg-core";
|
||||
|
||||
import Layout from "~/components/basic/Layout";
|
||||
@@ -16,6 +17,15 @@ config.autoAddCss = false;
|
||||
const App = ({ Component, pageProps, ...appProps }) => {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const storedLang = localStorage.getItem("lang");
|
||||
if (router.locale ?? "en" !== storedLang ?? "en") {
|
||||
router.push(router.asPath, router.asPath, {
|
||||
locale: storedLang ?? "en",
|
||||
});
|
||||
}
|
||||
}, [router.locale, router.pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
// Init for auto capturing
|
||||
const telemetry = new Telemetry().getInstance();
|
||||
@@ -52,7 +62,7 @@ const App = ({ Component, pageProps, ...appProps }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
export default appWithTranslation(App);
|
||||
|
||||
{
|
||||
/* <Script
|
||||
|
||||
@@ -13,10 +13,12 @@ import {
|
||||
faUserPlus
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
import onboardingCheck from '~/components/utilities/checks/OnboardingCheck';
|
||||
|
||||
import registerUserAction from '../api/userActions/registerUserAction';
|
||||
import { getTranslatedServerSideProps } from '~/components/utilities/withTranslateProps';
|
||||
|
||||
type ItemProps = {
|
||||
text: string;
|
||||
@@ -139,6 +141,8 @@ export default function Home() {
|
||||
const [hasUserPushedSecrets, setHasUserPushedSecrets] = useState(false);
|
||||
const [usersInOrg, setUsersInOrg] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
onboardingCheck({
|
||||
setHasUserClickedIntro,
|
||||
@@ -226,3 +230,5 @@ export default function Home() {
|
||||
}
|
||||
|
||||
Home.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(["home"]);
|
||||
|
||||
@@ -2,14 +2,21 @@ import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import {
|
||||
faArrowRight,
|
||||
faCheck,
|
||||
faRotate,
|
||||
faX,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import ActivateBotDialog from "~/components/basic/dialog/ActivateBotDialog";
|
||||
import IntegrationAccessTokenDialog from "~/components/basic/dialog/IntegrationAccessTokenDialog";
|
||||
import CloudIntegrationSection from "~/components/integrations/CloudIntegrationSection";
|
||||
import FrameworkIntegrationSection from "~/components/integrations/FrameworkIntegrationSection";
|
||||
import Integration from "~/components/integrations/Integration";
|
||||
import IntegrationSection from "~/components/integrations/IntegrationSection";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import frameworkIntegrationOptions from "../../public/json/frameworkIntegrations.json";
|
||||
import getBot from "../api/bot/getBot";
|
||||
@@ -35,6 +42,8 @@ export default function Integrations() {
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
try {
|
||||
// get cloud integration options
|
||||
@@ -181,18 +190,17 @@ export default function Integrations() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Dashboard</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("integrations:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content="Manage your .env files in seconds" />
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files."
|
||||
/>
|
||||
<meta name="og:description" content={t("integrations:description")} />
|
||||
</Head>
|
||||
<div className="w-full max-h-96 pb-2 h-screen max-h-[calc(100vh-10px)] overflow-y-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||
<NavHeader
|
||||
pageName="Project Integrations"
|
||||
pageName={t("integrations:title")}
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<ActivateBotDialog
|
||||
@@ -229,3 +237,7 @@ export default function Integrations() {
|
||||
}
|
||||
|
||||
Integrations.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"integrations",
|
||||
]);
|
||||
|
||||
@@ -1,24 +1,34 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { faWarning } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faWarning } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import Error from '~/components/basic/Error';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import attemptLogin from '~/utilities/attemptLogin';
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import Error from "~/components/basic/Error";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import { getTranslatedStaticProps } from "~/components/utilities/withTranslateProps";
|
||||
import attemptLogin from "~/utilities/attemptLogin";
|
||||
|
||||
import getWorkspaces from './api/workspace/getWorkspaces';
|
||||
import getWorkspaces from "./api/workspace/getWorkspaces";
|
||||
import ListBox from "~/components/basic/Listbox";
|
||||
|
||||
export default function Login() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [errorLogin, setErrorLogin] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const lang = router.locale ?? "en";
|
||||
|
||||
const setLanguage = async (to: string) => {
|
||||
router.push("/login", "/login", { locale: to });
|
||||
localStorage.setItem("lang", to);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const redirectToDashboard = async () => {
|
||||
@@ -26,9 +36,9 @@ export default function Login() {
|
||||
try {
|
||||
const userWorkspaces = await getWorkspaces();
|
||||
userWorkspace = userWorkspaces[0]._id;
|
||||
router.push('/dashboard/' + userWorkspace);
|
||||
router.push("/dashboard/" + userWorkspace);
|
||||
} catch (error) {
|
||||
console.log('Error - Not logged in yet');
|
||||
console.log("Error - Not logged in yet");
|
||||
}
|
||||
};
|
||||
redirectToDashboard();
|
||||
@@ -49,7 +59,7 @@ export default function Login() {
|
||||
setErrorLogin,
|
||||
router,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
).then(() => {
|
||||
setTimeout(function () {
|
||||
setIsLoading(false);
|
||||
@@ -60,14 +70,11 @@ export default function Login() {
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col justify-start px-6">
|
||||
<Head>
|
||||
<title>Login</title>
|
||||
<title>{t("common:head-title", { title: t("login:title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content="Log In to Infisical" />
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files."
|
||||
/>
|
||||
<meta property="og:title" content={t("login:og-title") ?? ""} />
|
||||
<meta name="og:description" content={t("login:og-description") ?? ""} />
|
||||
</Head>
|
||||
<Link href="/">
|
||||
<div className="flex justify-center mb-8 mt-20 cursor-pointer">
|
||||
@@ -80,15 +87,16 @@ export default function Login() {
|
||||
</div>
|
||||
</Link>
|
||||
<form
|
||||
onChange={() => setErrorLogin(false)} onSubmit={(e) => e.preventDefault()}
|
||||
onChange={() => setErrorLogin(false)}
|
||||
onSubmit={(e) => e.preventDefault()}
|
||||
>
|
||||
<div className="bg-bunker w-full max-w-md mx-auto h-7/12 py-4 pt-8 px-6 rounded-xl drop-shadow-xl">
|
||||
<p className="text-3xl w-max mx-auto flex justify-center font-semibold text-bunker-100 mb-6">
|
||||
Log in to your account
|
||||
{t("login:login")}
|
||||
</p>
|
||||
<div className="flex items-center justify-center w-full md:p-2 rounded-lg mt-4 md:mt-0 max-h-24 md:max-h-28">
|
||||
<InputField
|
||||
label="Email"
|
||||
label={t("common:email")}
|
||||
onChangeHandler={setEmail}
|
||||
type="email"
|
||||
value={email}
|
||||
@@ -99,7 +107,7 @@ export default function Login() {
|
||||
</div>
|
||||
<div className="relative flex items-center justify-center w-full md:p-2 rounded-lg md:mt-2 mt-6 max-h-24 md:max-h-28">
|
||||
<InputField
|
||||
label="Password"
|
||||
label={t("common:password")}
|
||||
onChangeHandler={setPassword}
|
||||
type="password"
|
||||
value={password}
|
||||
@@ -112,12 +120,14 @@ export default function Login() {
|
||||
<Link href="/verify-email">Forgot password?</Link>
|
||||
</div>
|
||||
</div>
|
||||
{!isLoading && errorLogin && <Error text="Your email and/or password are wrong." />}
|
||||
{!isLoading && errorLogin && (
|
||||
<Error text="Your email and/or password are wrong." />
|
||||
)}
|
||||
<div className="flex flex-col items-center justify-center w-full md:p-2 max-h-20 max-w-md mt-4 mx-auto text-sm">
|
||||
<div className="text-l mt-6 m-8 px-8 py-3 text-lg">
|
||||
<Button
|
||||
type="submit"
|
||||
text="Log In"
|
||||
text={t("login:login") ?? ""}
|
||||
onButtonPressed={loginCheck}
|
||||
loading={isLoading}
|
||||
size="lg"
|
||||
@@ -131,21 +141,33 @@ export default function Login() {
|
||||
{false && (
|
||||
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-300 rounded-md max-w-md mx-auto mt-4">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-6 text-6xl" />
|
||||
We are experiencing minor technical difficulties. We are working on
|
||||
solving it right now. Please come back in a few minutes.
|
||||
{t("common:maintenance-alert")}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-row items-center justify-center md:pb-4 mt-4">
|
||||
<p className="text-sm flex justify-center text-gray-400 w-max">
|
||||
Need an Infisical account?
|
||||
{t("login:need-account")}
|
||||
</p>
|
||||
<Link href="/signup">
|
||||
<button className="text-primary-700 hover:text-primary duration-200 font-normal text-sm underline-offset-4 ml-1.5">
|
||||
Sign up here.
|
||||
{t("login:create-account")}
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
<div className="mt-4 flex items-center justify-center w-full">
|
||||
<div className="w-48 mx-auto">
|
||||
<ListBox
|
||||
selected={lang}
|
||||
onChange={setLanguage}
|
||||
data={["en", "ko"]}
|
||||
isFull
|
||||
text={`${t("common:language")}: `}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = getTranslatedStaticProps(["auth", "login"]);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import { faFolderOpen } from "@fortawesome/free-regular-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
export default function NoProjects() {
|
||||
return (
|
||||
@@ -31,3 +30,5 @@ export default function NoProjects() {
|
||||
}
|
||||
|
||||
NoProjects.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(["noprojects"]);
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
import { useState } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import { faCheck, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import passwordCheck from '~/components/utilities/checks/PasswordCheck';
|
||||
import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm';
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import passwordCheck from "~/components/utilities/checks/PasswordCheck";
|
||||
import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm";
|
||||
|
||||
import EmailVerifyOnPasswordReset from './api/auth/EmailVerifyOnPasswordReset';
|
||||
import getBackupEncryptedPrivateKey from './api/auth/getBackupEncryptedPrivateKey';
|
||||
import resetPasswordOnAccountRecovery from './api/auth/resetPasswordOnAccountRecovery';
|
||||
import EmailVerifyOnPasswordReset from "./api/auth/EmailVerifyOnPasswordReset";
|
||||
import getBackupEncryptedPrivateKey from "./api/auth/getBackupEncryptedPrivateKey";
|
||||
import resetPasswordOnAccountRecovery from "./api/auth/resetPasswordOnAccountRecovery";
|
||||
import { getTranslatedStaticProps } from "~/components/utilities/withTranslateProps";
|
||||
|
||||
const queryString = require('query-string');
|
||||
const nacl = require('tweetnacl');
|
||||
const jsrp = require('jsrp');
|
||||
nacl.util = require('tweetnacl-util');
|
||||
const queryString = require("query-string");
|
||||
const nacl = require("tweetnacl");
|
||||
const jsrp = require("jsrp");
|
||||
nacl.util = require("tweetnacl-util");
|
||||
const client = new jsrp.client();
|
||||
|
||||
export default function PasswordReset() {
|
||||
const router = useRouter();
|
||||
const parsedUrl = queryString.parse(router.asPath.split('?')[1]);
|
||||
const parsedUrl = queryString.parse(router.asPath.split("?")[1]);
|
||||
const token = parsedUrl.token;
|
||||
const email = parsedUrl.to?.replace(' ', '+').trim();
|
||||
const [verificationToken, setVerificationToken] = useState('');
|
||||
const email = parsedUrl.to?.replace(" ", "+").trim();
|
||||
const [verificationToken, setVerificationToken] = useState("");
|
||||
const [step, setStep] = useState(1);
|
||||
const [backupKey, setBackupKey] = useState('');
|
||||
const [privateKey, setPrivateKey] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [backupKey, setBackupKey] = useState("");
|
||||
const [privateKey, setPrivateKey] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [backupKeyError, setBackupKeyError] = useState(false);
|
||||
const [passwordErrorLength, setPasswordErrorLength] = useState(false);
|
||||
const [passwordErrorNumber, setPasswordErrorNumber] = useState(false);
|
||||
@@ -43,7 +44,7 @@ export default function PasswordReset() {
|
||||
ciphertext: result.encryptedPrivateKey,
|
||||
iv: result.iv,
|
||||
tag: result.tag,
|
||||
secret: backupKey
|
||||
secret: backupKey,
|
||||
})
|
||||
);
|
||||
setStep(3);
|
||||
@@ -60,7 +61,7 @@ export default function PasswordReset() {
|
||||
setPasswordErrorLength,
|
||||
setPasswordErrorNumber,
|
||||
setPasswordErrorLowerCase,
|
||||
currentErrorCheck: errorCheck
|
||||
currentErrorCheck: errorCheck,
|
||||
});
|
||||
|
||||
if (!errorCheck) {
|
||||
@@ -72,14 +73,14 @@ export default function PasswordReset() {
|
||||
.padStart(
|
||||
32 +
|
||||
(newPassword.slice(0, 32).length - new Blob([newPassword]).size),
|
||||
'0'
|
||||
)
|
||||
"0"
|
||||
),
|
||||
}) as { ciphertext: string; iv: string; tag: string };
|
||||
|
||||
client.init(
|
||||
{
|
||||
username: email,
|
||||
password: newPassword
|
||||
password: newPassword,
|
||||
},
|
||||
async () => {
|
||||
client.createVerifier(
|
||||
@@ -90,12 +91,12 @@ export default function PasswordReset() {
|
||||
iv,
|
||||
tag,
|
||||
salt: result.salt,
|
||||
verifier: result.verifier
|
||||
verifier: result.verifier,
|
||||
});
|
||||
|
||||
// if everything works, go the main dashboard page.
|
||||
if (response?.status === 200) {
|
||||
router.push('/login');
|
||||
router.push("/login");
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -122,14 +123,14 @@ export default function PasswordReset() {
|
||||
onButtonPressed={async () => {
|
||||
const response = await EmailVerifyOnPasswordReset({
|
||||
email,
|
||||
code: token
|
||||
code: token,
|
||||
});
|
||||
if (response.status == 200) {
|
||||
setVerificationToken((await response.json()).token);
|
||||
setStep(2);
|
||||
} else {
|
||||
console.log('ERROR', response);
|
||||
router.push('/email-not-verified');
|
||||
console.log("ERROR", response);
|
||||
router.push("/email-not-verified");
|
||||
}
|
||||
}}
|
||||
size="lg"
|
||||
@@ -195,7 +196,7 @@ export default function PasswordReset() {
|
||||
setPasswordErrorLength,
|
||||
setPasswordErrorNumber,
|
||||
setPasswordErrorLowerCase,
|
||||
currentErrorCheck: false
|
||||
currentErrorCheck: false,
|
||||
});
|
||||
}}
|
||||
type="password"
|
||||
@@ -224,7 +225,7 @@ export default function PasswordReset() {
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLength ? 'text-gray-400' : 'text-gray-600'
|
||||
passwordErrorLength ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
@@ -241,7 +242,7 @@ export default function PasswordReset() {
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'
|
||||
passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
@@ -258,7 +259,7 @@ export default function PasswordReset() {
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorNumber ? 'text-gray-400' : 'text-gray-600'
|
||||
passwordErrorNumber ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
@@ -288,3 +289,5 @@ export default function PasswordReset() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = getTranslatedStaticProps([]);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import { useTranslation } from "next-i18next";
|
||||
|
||||
import Plan from "~/components/billing/Plan";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import { STRIPE_PRODUCT_PRO, STRIPE_PRODUCT_STARTER } from "~/utilities/config";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import getOrganizationSubscriptions from "../../api/organization/GetOrgSubscription";
|
||||
import getOrganizationUsers from "../../api/organization/GetOrgUsers";
|
||||
@@ -12,36 +14,38 @@ export default function SettingsBilling() {
|
||||
let [currentPlan, setCurrentPlan] = useState("");
|
||||
let [numUsers, setNumUsers] = useState("");
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const plans = [
|
||||
{
|
||||
key: 1,
|
||||
name: "Starter",
|
||||
price: "Free",
|
||||
priceExplanation: "up to 5 team members",
|
||||
text: "Manage any project with 5 members for free!",
|
||||
subtext: "$5 per member/month afterwards.",
|
||||
buttonTextMain: "Downgrade",
|
||||
buttonTextSecondary: "Learn More",
|
||||
name: t("billing:starter.name"),
|
||||
price: t("billing:free"),
|
||||
priceExplanation: t("billing:starter.price-explanation"),
|
||||
text: t("billing:starter.text"),
|
||||
subtext: t("billing:starter.subtext"),
|
||||
buttonTextMain: t("billing:downgrade"),
|
||||
buttonTextSecondary: t("billing:learn-more"),
|
||||
current: currentPlan == STRIPE_PRODUCT_STARTER,
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: "Professional",
|
||||
name: t("billing:professional.name"),
|
||||
price: "$9",
|
||||
priceExplanation: "/member/month",
|
||||
subtext: "Includes unlimited projects & members.",
|
||||
text: "Keep up with key management as you grow.",
|
||||
buttonTextMain: "Upgrade",
|
||||
buttonTextSecondary: "Learn More",
|
||||
priceExplanation: t("billing:professional.price-explanation"),
|
||||
subtext: t("billing:professional.subtext"),
|
||||
text: t("billing:professional.text"),
|
||||
buttonTextMain: t("billing:upgrade"),
|
||||
buttonTextSecondary: t("billing:learn-more"),
|
||||
current: currentPlan == STRIPE_PRODUCT_PRO,
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
name: "Enterprise",
|
||||
price: "Custom Pricing",
|
||||
text: "More control for advanced organizations.",
|
||||
buttonTextMain: "Schedule a Demo",
|
||||
buttonTextSecondary: "Learn More",
|
||||
name: t("billing:enterprise.name"),
|
||||
price: t("billing:custom-pricing"),
|
||||
text: t("billing:enterprise.text"),
|
||||
buttonTextMain: t("billing:schedule-demo"),
|
||||
buttonTextSecondary: t("billing:learn-more"),
|
||||
current: false,
|
||||
},
|
||||
];
|
||||
@@ -61,30 +65,32 @@ export default function SettingsBilling() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings - Billing</title>
|
||||
<title>{t("common:head-title", { title: t("billing:title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Usage & Billing" />
|
||||
<NavHeader pageName={t("billing:title")} />
|
||||
<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">
|
||||
Usage & Billing
|
||||
{t("billing:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your {"organization's"} subscription here.
|
||||
{t("billing:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50">
|
||||
<p className="text-xl font-semibold">Subscription</p>
|
||||
<p className="text-xl font-semibold">{t("billing:subscription")}</p>
|
||||
<div className="flex flex-row mt-4 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan key={plan.name} plan={plan} />
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xl font-bold mt-12">Current Usage</p>
|
||||
<p className="text-xl font-bold mt-12">
|
||||
{t("billing:current-usage")}
|
||||
</p>
|
||||
<div className="flex flex-row">
|
||||
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 flex justify-center items-center flex flex-col">
|
||||
<p className="text-6xl font-bold">{numUsers}</p>
|
||||
@@ -107,3 +113,8 @@ export default function SettingsBilling() {
|
||||
}
|
||||
|
||||
SettingsBilling.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"settings",
|
||||
"billing",
|
||||
]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import {
|
||||
faMagnifyingGlass,
|
||||
faPlus,
|
||||
@@ -9,13 +10,14 @@ import {
|
||||
import { faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import AddIncidentContactDialog from '~/components/basic/dialog/AddIncidentContactDialog';
|
||||
import AddUserDialog from '~/components/basic/dialog/AddUserDialog';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import UserTable from '~/components/basic/table/UserTable';
|
||||
import NavHeader from '~/components/navigation/NavHeader';
|
||||
import guidGenerator from '~/utilities/randomId';
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import AddIncidentContactDialog from "~/components/basic/dialog/AddIncidentContactDialog";
|
||||
import AddUserDialog from "~/components/basic/dialog/AddUserDialog";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import UserTable from "~/components/basic/table/UserTable";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import guidGenerator from "~/utilities/randomId";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import addUserToOrg from '../../api/organization/addUserToOrg';
|
||||
import deleteIncidentContact from '../../api/organization/deleteIncidentContact';
|
||||
@@ -49,6 +51,8 @@ export default function SettingsOrg() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [currentPlan, setCurrentPlan] = useState('');
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
let org = await getOrganization({
|
||||
orgId: localStorage.getItem('orgData.id')
|
||||
@@ -156,12 +160,14 @@ export default function SettingsOrg() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-org:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Organization Settings" />
|
||||
<NavHeader pageName={t("settings-org:title")} />
|
||||
<AddIncidentContactDialog
|
||||
isOpen={isAddIncidentContactOpen}
|
||||
closeModal={closeAddIncidentContactModal}
|
||||
@@ -172,10 +178,10 @@ export default function SettingsOrg() {
|
||||
<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">
|
||||
Organization Settings
|
||||
{t("settings-org:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your organization here.
|
||||
{t("settings-org:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,7 +191,7 @@ export default function SettingsOrg() {
|
||||
<div className="bg-white/5 rounded-md px-6 py-4 flex flex-col items-start flex flex-col items-start w-full mb-6">
|
||||
<div className="max-h-28 w-full max-w-md mr-auto">
|
||||
<p className="font-semibold mr-4 text-gray-200 text-xl mb-2">
|
||||
Display Name
|
||||
{t("common:display-name")}
|
||||
</p>
|
||||
<InputField
|
||||
// label="Organization Name"
|
||||
@@ -199,13 +205,13 @@ export default function SettingsOrg() {
|
||||
<div className="flex justify-start w-full">
|
||||
<div className={`flex justify-start max-w-sm mt-4 mb-2`}>
|
||||
<Button
|
||||
text="Save Changes"
|
||||
text={t("common:save-changes")}
|
||||
onButtonPressed={() => submitChanges(orgName)}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={buttonReady}
|
||||
iconDisabled={faCheck}
|
||||
textDisabled="Saved"
|
||||
textDisabled={t("common:saved")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,11 +220,10 @@ export default function SettingsOrg() {
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-2 flex flex-col items-start flex flex-col items-start w-full mb-6">
|
||||
<p className="font-semibold mr-4 text-white text-xl">
|
||||
Organization Members
|
||||
{t("section-members:org-members")}
|
||||
</p>
|
||||
<p className="mr-4 text-gray-400 mt-2 mb-2">
|
||||
Manage members of your organization. These users could
|
||||
afterwards be formed into projects.
|
||||
{t("section-members:org-members-description")}
|
||||
</p>
|
||||
<AddUserDialog
|
||||
isOpen={isAddUserOpen}
|
||||
@@ -241,12 +246,12 @@ export default function SettingsOrg() {
|
||||
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchUsers}
|
||||
onChange={(e) => setSearchUsers(e.target.value)}
|
||||
placeholder={'Search members...'}
|
||||
placeholder={t("section-members:search-members")}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 ml-2 min-w-max flex flex-row items-start justify-start">
|
||||
<Button
|
||||
text="Add Member"
|
||||
text={t("section-members:add-member")}
|
||||
onButtonPressed={openAddUserModal}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -276,16 +281,15 @@ export default function SettingsOrg() {
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
Incident Contacts
|
||||
{t("section-incident:incident-contacts")}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 mb-2 min-w-max">
|
||||
These contacts will be notified in the unlikely event of a
|
||||
severe incident.
|
||||
{t("section-incident:incident-contacts-description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-4 mb-2 min-w-max flex flex-row items-end justify-end justify-center">
|
||||
<Button
|
||||
text="Add Contact"
|
||||
text={t("section-incident:add-contact")}
|
||||
onButtonPressed={openAddIncidentContactModal}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -302,7 +306,7 @@ export default function SettingsOrg() {
|
||||
className="pl-2 text-gray-400 rounded-tr-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchIncidentContact}
|
||||
onChange={(e) => setSearchIncidentContact(e.target.value)}
|
||||
placeholder={'Search...'}
|
||||
placeholder={t("common:search")}
|
||||
/>
|
||||
</div>
|
||||
{incidentContacts?.filter((email) =>
|
||||
@@ -330,7 +334,9 @@ export default function SettingsOrg() {
|
||||
))
|
||||
) : (
|
||||
<div className="w-full flex flex-row justify-center mt-6 max-w-4xl ml-6">
|
||||
<p className="text-gray-400">No incident contacts found.</p>
|
||||
<p className="text-gray-400">
|
||||
{t("section-incident:no-incident-contacts")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -378,3 +384,10 @@ export default function SettingsOrg() {
|
||||
}
|
||||
|
||||
SettingsOrg.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"settings",
|
||||
"settings-org",
|
||||
"section-incident",
|
||||
"section-members",
|
||||
]);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faCheck, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import ListBox from "~/components/basic/Listbox";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import changePassword from "~/components/utilities/cryptography/changePassword";
|
||||
import issueBackupKey from "~/components/utilities/cryptography/issueBackupKey";
|
||||
import passwordCheck from "~/utilities/checks/PasswordCheck";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import getUser from "../../api/user/getUser";
|
||||
|
||||
@@ -26,6 +30,15 @@ export default function PersonalSettings() {
|
||||
const [backupKeyIssued, setBackupKeyIssued] = useState(false);
|
||||
const [backupKeyError, setBackupKeyError] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const lang = router.locale ?? "en";
|
||||
|
||||
const setLanguage = async (to) => {
|
||||
router.push(router.asPath, router.asPath, { locale: to });
|
||||
localStorage.setItem("lang", to);
|
||||
};
|
||||
|
||||
useEffect(async () => {
|
||||
let user = await getUser();
|
||||
setPersonalEmail(user.email);
|
||||
@@ -35,19 +48,24 @@ export default function PersonalSettings() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Personal Settings</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-personal:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Personal Settings" isProjectRelated={false} />
|
||||
<NavHeader
|
||||
pageName={t("settings-personal:title")}
|
||||
isProjectRelated={false}
|
||||
/>
|
||||
<div className="flex flex-row justify-between items-center ml-6 mt-8 mb-6 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">
|
||||
Personal Settings
|
||||
{t("settings-personal:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
View and manage your personal information here.
|
||||
{t("settings-personal:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,17 +118,32 @@ export default function PersonalSettings() {
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-6 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4">
|
||||
<p className="text-xl font-semibold self-start">
|
||||
{t("settings-personal:change-language")}
|
||||
</p>
|
||||
<div className="max-h-28 w-ful mt-4">
|
||||
<ListBox
|
||||
selected={lang}
|
||||
onChange={setLanguage}
|
||||
data={["en", "ko"]}
|
||||
width="full"
|
||||
text={`${t("common:language")}: `}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 rounded-md px-6 pt-5 pb-6 flex flex-col items-start flex flex-col items-start w-full mb-6">
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
Change password
|
||||
{t("section-password:change")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-xl w-full">
|
||||
<InputField
|
||||
label="Current Password"
|
||||
label={t("section-password:current")}
|
||||
onChangeHandler={(password) => {
|
||||
setCurrentPassword(password);
|
||||
}}
|
||||
@@ -118,13 +151,13 @@ export default function PersonalSettings() {
|
||||
value={currentPassword}
|
||||
isRequired
|
||||
error={currentPasswordError}
|
||||
errorText="The current password may be wrong"
|
||||
errorText={t("section-password:current-wrong")}
|
||||
autoComplete="current-password"
|
||||
id="current-password"
|
||||
/>
|
||||
<div className="py-2"></div>
|
||||
<InputField
|
||||
label="New Password"
|
||||
label={t("section-password:new")}
|
||||
onChangeHandler={(password) => {
|
||||
setNewPassword(password);
|
||||
passwordCheck({
|
||||
@@ -152,7 +185,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
Password should contain at least:
|
||||
{t("section-password:validate-base")}
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
@@ -171,7 +204,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorLength ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
{t("section-password:validate-length")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -193,7 +226,7 @@ export default function PersonalSettings() {
|
||||
: "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
{t("section-password:validate-case")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -213,7 +246,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorNumber ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
{t("section-password:validate-number")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -222,7 +255,7 @@ export default function PersonalSettings() {
|
||||
)}
|
||||
<div className="flex flex-row items-center mt-3 w-52 pr-3">
|
||||
<Button
|
||||
text="Change Password"
|
||||
text={t("section-password:change")}
|
||||
onButtonPressed={() => {
|
||||
if (
|
||||
!passwordErrorLength &&
|
||||
@@ -251,7 +284,7 @@ export default function PersonalSettings() {
|
||||
passwordErrorNumber
|
||||
)
|
||||
}
|
||||
textDisabled="Change Password"
|
||||
textDisabled={t("section-password:change")}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
@@ -266,34 +299,32 @@ export default function PersonalSettings() {
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
Emergency Kit
|
||||
{t("settings-personal:emergency.name")}
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 min-w-max">
|
||||
Your Emergency Kit contains the information you’ll need to
|
||||
sign in to your Infisical account.
|
||||
{t("settings-personal:emergency.text1")}
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 mb-5 min-w-max">
|
||||
Only the latest issued Emergency Kit remains valid. To get a
|
||||
new Emergency Kit, verify your password.
|
||||
{t("settings-personal:emergency.text2")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-xl mb-4">
|
||||
<InputField
|
||||
label="Current Password"
|
||||
label={t("section-password:current")}
|
||||
onChangeHandler={setBackupPassword}
|
||||
type="password"
|
||||
value={backupPassword}
|
||||
isRequired
|
||||
error={backupKeyError}
|
||||
errorText="The current password is wrong"
|
||||
errorText={t("section-password:current-wrong")}
|
||||
autoComplete="current-password"
|
||||
id="current-password"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row items-center mt-3 w-full w-60">
|
||||
<Button
|
||||
text="Download Emergency Kit"
|
||||
text={t("settings-personal:emergency.download")}
|
||||
onButtonPressed={() => {
|
||||
issueBackupKey({
|
||||
email: personalEmail,
|
||||
@@ -306,7 +337,7 @@ export default function PersonalSettings() {
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={backupPassword != ""}
|
||||
textDisabled="Download Emergency Kit"
|
||||
textDisabled={t("settings-personal:emergency.download")}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
@@ -324,3 +355,9 @@ export default function PersonalSettings() {
|
||||
}
|
||||
|
||||
PersonalSettings.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"settings",
|
||||
"settings-personal",
|
||||
"section-password",
|
||||
]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faCheck, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
@@ -8,6 +9,7 @@ import AddServiceTokenDialog from "~/components/basic/dialog/AddServiceTokenDial
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import ServiceTokenTable from "~/components/basic/table/ServiceTokenTable";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import getServiceTokens from "../../api/serviceToken/getServiceTokens";
|
||||
import deleteWorkspace from "../../api/workspace/deleteWorkspace";
|
||||
@@ -25,6 +27,8 @@ export default function SettingsBasic() {
|
||||
let [isAddServiceTokenDialogOpen, setIsAddServiceTokenDialogOpen] =
|
||||
useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(async () => {
|
||||
let userWorkspaces = await getWorkspaces();
|
||||
userWorkspaces.map((userWorkspace) => {
|
||||
@@ -89,7 +93,9 @@ export default function SettingsBasic() {
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<Head>
|
||||
<title>Settings</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-project:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<AddServiceTokenDialog
|
||||
@@ -100,14 +106,17 @@ export default function SettingsBasic() {
|
||||
/>
|
||||
<div className="flex flex-row mr-6 max-w-5xl">
|
||||
<div className="w-full max-h-screen pb-2 overflow-y-auto">
|
||||
<NavHeader pageName="Project Settings" isProjectRelated={true} />
|
||||
<NavHeader
|
||||
pageName={t("settings-project:title")}
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<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">
|
||||
Project Settings
|
||||
{t("settings-project:title")}
|
||||
</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
These settings only apply to the currently selected Project.
|
||||
{t("settings-project:description")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,7 +124,9 @@ export default function SettingsBasic() {
|
||||
<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 pt-6 pb-4 flex flex-col items-start flex flex-col items-start w-full mb-6 pt-2">
|
||||
<p className="text-xl font-semibold mb-4">Display Name</p>
|
||||
<p className="text-xl font-semibold mb-4">
|
||||
{t("common:display-name")}
|
||||
</p>
|
||||
<div className="max-h-28 w-full max-w-md mr-auto">
|
||||
<InputField
|
||||
onChangeHandler={modifyWorkspaceName}
|
||||
@@ -128,7 +139,7 @@ export default function SettingsBasic() {
|
||||
<div className="flex justify-start w-full">
|
||||
<div className={`flex justify-start max-w-sm mt-4 mb-2`}>
|
||||
<Button
|
||||
text="Save Changes"
|
||||
text={t("common:save-changes")}
|
||||
onButtonPressed={() => submitChanges(workspaceName)}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -140,15 +151,14 @@ export default function SettingsBasic() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-2 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4">
|
||||
<p className="text-xl font-semibold self-start">Project ID</p>
|
||||
<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">
|
||||
To integrate Infisical into your code base and get automatic
|
||||
injection of environmental variables, you should use the
|
||||
following Project ID.
|
||||
{t("settings-project:project-id-description")}
|
||||
</p>
|
||||
<p className="text-base text-gray-400 font-normal self-start">
|
||||
For more guidance, including code snipets for various
|
||||
languages and frameworks, see{" "}
|
||||
{t("settings-project:project-id-description2")}
|
||||
{/* eslint-disable-next-line react/jsx-no-target-blank */}
|
||||
<a
|
||||
href="https://infisical.com/docs/getting-started/introduction"
|
||||
@@ -156,7 +166,7 @@ export default function SettingsBasic() {
|
||||
rel="noopener"
|
||||
className="text-primary hover:opacity-80 duration-200"
|
||||
>
|
||||
Infisical Docs.
|
||||
{t("settings-project:docs")}
|
||||
</a>
|
||||
</p>
|
||||
<div className="max-h-28 w-ful">
|
||||
@@ -166,7 +176,7 @@ export default function SettingsBasic() {
|
||||
placeholder=""
|
||||
isRequired
|
||||
static
|
||||
text="This is your project's auto-generated unique identifier. It can't be changed."
|
||||
text={t("settings-project:auto-generated")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -174,16 +184,15 @@ export default function SettingsBasic() {
|
||||
<div className="flex flex-row justify-between w-full">
|
||||
<div className="flex flex-col w-full">
|
||||
<p className="text-xl font-semibold mb-3">
|
||||
Service Tokens
|
||||
{t("section-token:service-tokens")}
|
||||
</p>
|
||||
<p className="text-base text-gray-400 mb-4">
|
||||
Every service token is specific to you, a certain
|
||||
project and a certain environment within this project.
|
||||
{t("section-token:service-tokens-description")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-48">
|
||||
<Button
|
||||
text="Add New Token"
|
||||
text={t("section-token:add-new")}
|
||||
onButtonPressed={() => {
|
||||
setIsAddServiceTokenDialogOpen(true);
|
||||
}}
|
||||
@@ -237,15 +246,15 @@ export default function SettingsBasic() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-6 border-l border-red pl-6 flex flex-col items-start flex flex-col items-start w-full mb-6 mt-4 pb-4 pt-2">
|
||||
<p className="text-xl font-bold text-red">Danger Zone</p>
|
||||
<p className="text-xl font-bold text-red">
|
||||
{t("settings-project:danger-zone")}
|
||||
</p>
|
||||
<p className="mt-2 text-md text-gray-400">
|
||||
As soon as you delete this project, you will not be able to undo
|
||||
it. This will immediately remove all the keys. If you still want
|
||||
to do that, please enter the name of the project below.
|
||||
{t("settings-project:danger-zone-note")}
|
||||
</p>
|
||||
<div className="max-h-28 w-full max-w-md mr-auto mt-4">
|
||||
<InputField
|
||||
label="Project to be Deleted"
|
||||
label={t("settings-project:project-to-delete")}
|
||||
onChangeHandler={setWorkspaceToBeDeletedName}
|
||||
type="varName"
|
||||
value={workspaceToBeDeletedName}
|
||||
@@ -258,11 +267,10 @@ export default function SettingsBasic() {
|
||||
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}
|
||||
>
|
||||
Delete Project
|
||||
{t("settings-project:delete-project")}
|
||||
</button>
|
||||
<p className="mt-0.5 ml-1 text-xs text-gray-500">
|
||||
Note: You can only delete a project in case you have more than
|
||||
one.
|
||||
{t("settings-project:delete-project-note")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -273,3 +281,9 @@ export default function SettingsBasic() {
|
||||
}
|
||||
|
||||
SettingsBasic.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"settings",
|
||||
"settings-project",
|
||||
"section-token",
|
||||
]);
|
||||
|
||||
@@ -1,71 +1,73 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import ReactCodeInput from 'react-code-input';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { faCheck, faWarning, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useEffect, useState } from "react";
|
||||
import ReactCodeInput from "react-code-input";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faCheck, faWarning, faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import Error from '~/components/basic/Error';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import Aes256Gcm from '~/components/utilities/cryptography/aes-256-gcm';
|
||||
import issueBackupKey from '~/components/utilities/cryptography/issueBackupKey';
|
||||
import attemptLogin from '~/utilities/attemptLogin';
|
||||
import passwordCheck from '~/utilities/checks/PasswordCheck';
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import Error from "~/components/basic/Error";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import Aes256Gcm from "~/components/utilities/cryptography/aes-256-gcm";
|
||||
import issueBackupKey from "~/components/utilities/cryptography/issueBackupKey";
|
||||
import { getTranslatedStaticProps } from "~/components/utilities/withTranslateProps";
|
||||
import attemptLogin from "~/utilities/attemptLogin";
|
||||
import passwordCheck from "~/utilities/checks/PasswordCheck";
|
||||
|
||||
import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode';
|
||||
import completeAccountInformationSignup from './api/auth/CompleteAccountInformationSignup';
|
||||
import sendVerificationEmail from './api/auth/SendVerificationEmail';
|
||||
import getWorkspaces from './api/workspace/getWorkspaces';
|
||||
import checkEmailVerificationCode from "./api/auth/CheckEmailVerificationCode";
|
||||
import completeAccountInformationSignup from "./api/auth/CompleteAccountInformationSignup";
|
||||
import sendVerificationEmail from "./api/auth/SendVerificationEmail";
|
||||
import getWorkspaces from "./api/workspace/getWorkspaces";
|
||||
|
||||
// const ReactCodeInput = dynamic(import("react-code-input"));
|
||||
const nacl = require('tweetnacl');
|
||||
const jsrp = require('jsrp');
|
||||
nacl.util = require('tweetnacl-util');
|
||||
const nacl = require("tweetnacl");
|
||||
const jsrp = require("jsrp");
|
||||
nacl.util = require("tweetnacl-util");
|
||||
const client = new jsrp.client();
|
||||
|
||||
// The stye for the verification code input
|
||||
const props = {
|
||||
inputStyle: {
|
||||
fontFamily: 'monospace',
|
||||
margin: '4px',
|
||||
MozAppearance: 'textfield',
|
||||
width: '55px',
|
||||
borderRadius: '5px',
|
||||
fontSize: '24px',
|
||||
height: '55px',
|
||||
paddingLeft: '7',
|
||||
backgroundColor: '#0d1117',
|
||||
color: 'white',
|
||||
border: '1px solid gray',
|
||||
textAlign: 'center',
|
||||
fontFamily: "monospace",
|
||||
margin: "4px",
|
||||
MozAppearance: "textfield",
|
||||
width: "55px",
|
||||
borderRadius: "5px",
|
||||
fontSize: "24px",
|
||||
height: "55px",
|
||||
paddingLeft: "7",
|
||||
backgroundColor: "#0d1117",
|
||||
color: "white",
|
||||
border: "1px solid gray",
|
||||
textAlign: "center",
|
||||
},
|
||||
} as const;
|
||||
const propsPhone = {
|
||||
inputStyle: {
|
||||
fontFamily: 'monospace',
|
||||
margin: '4px',
|
||||
MozAppearance: 'textfield',
|
||||
width: '40px',
|
||||
borderRadius: '5px',
|
||||
fontSize: '24px',
|
||||
height: '40px',
|
||||
paddingLeft: '7',
|
||||
backgroundColor: '#0d1117',
|
||||
color: 'white',
|
||||
border: '1px solid gray',
|
||||
textAlign: 'center',
|
||||
fontFamily: "monospace",
|
||||
margin: "4px",
|
||||
MozAppearance: "textfield",
|
||||
width: "40px",
|
||||
borderRadius: "5px",
|
||||
fontSize: "24px",
|
||||
height: "40px",
|
||||
paddingLeft: "7",
|
||||
backgroundColor: "#0d1117",
|
||||
color: "white",
|
||||
border: "1px solid gray",
|
||||
textAlign: "center",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export default function SignUp() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [firstName, setFirstName] = useState('');
|
||||
const [lastName, setLastName] = useState('');
|
||||
const [code, setCode] = useState('');
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [code, setCode] = useState("");
|
||||
const [codeError, setCodeError] = useState(false);
|
||||
const [firstNameError, setFirstNameError] = useState(false);
|
||||
const [lastNameError, setLastNameError] = useState(false);
|
||||
@@ -76,23 +78,26 @@ export default function SignUp() {
|
||||
const [passwordErrorSpecialChar, setPasswordErrorSpecialChar] =
|
||||
useState(false);
|
||||
const [emailError, setEmailError] = useState(false);
|
||||
const [emailErrorMessage, setEmailErrorMessage] = useState('');
|
||||
const [emailErrorMessage, setEmailErrorMessage] = useState("");
|
||||
const [step, setStep] = useState(1);
|
||||
const router = useRouter();
|
||||
const [errorLogin, setErrorLogin] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isResendingVerificationEmail, setIsResendingVerificationEmail] = useState(false);
|
||||
const [isResendingVerificationEmail, setIsResendingVerificationEmail] =
|
||||
useState(false);
|
||||
const [backupKeyError, setBackupKeyError] = useState(false);
|
||||
const [verificationToken, setVerificationToken] = useState('');
|
||||
const [verificationToken, setVerificationToken] = useState("");
|
||||
const [backupKeyIssued, setBackupKeyIssued] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
const tryAuth = async () => {
|
||||
try {
|
||||
const userWorkspaces = await getWorkspaces();
|
||||
router.push('/dashboard/' + userWorkspaces[0]._id);
|
||||
router.push("/dashboard/" + userWorkspaces[0]._id);
|
||||
} catch (error) {
|
||||
console.log('Error - Not logged in yet');
|
||||
console.log("Error - Not logged in yet");
|
||||
}
|
||||
};
|
||||
tryAuth();
|
||||
@@ -110,7 +115,7 @@ export default function SignUp() {
|
||||
} else if (step == 2) {
|
||||
// Checking if the code matches the email.
|
||||
const response = await checkEmailVerificationCode({ email, code });
|
||||
if (response.status === 200 || code == '111222') {
|
||||
if (response.status === 200 || code == "111222") {
|
||||
setVerificationToken((await response.json()).token);
|
||||
setStep(3);
|
||||
} else {
|
||||
@@ -128,15 +133,15 @@ export default function SignUp() {
|
||||
let emailCheckBool = false;
|
||||
if (!email) {
|
||||
setEmailError(true);
|
||||
setEmailErrorMessage('Please enter your email.');
|
||||
setEmailErrorMessage("Please enter your email.");
|
||||
emailCheckBool = true;
|
||||
} else if (
|
||||
!email.includes('@') ||
|
||||
!email.includes('.') ||
|
||||
!email.includes("@") ||
|
||||
!email.includes(".") ||
|
||||
!/[a-z]/.test(email)
|
||||
) {
|
||||
setEmailError(true);
|
||||
setEmailErrorMessage('Please enter a valid email.');
|
||||
setEmailErrorMessage("Please enter a valid email.");
|
||||
emailCheckBool = true;
|
||||
} else {
|
||||
setEmailError(false);
|
||||
@@ -188,11 +193,11 @@ export default function SignUp() {
|
||||
.slice(0, 32)
|
||||
.padStart(
|
||||
32 + (password.slice(0, 32).length - new Blob([password]).size),
|
||||
'0',
|
||||
"0"
|
||||
),
|
||||
}) as { ciphertext: string; iv: string; tag: string };
|
||||
|
||||
localStorage.setItem('PRIVATE_KEY', PRIVATE_KEY);
|
||||
localStorage.setItem("PRIVATE_KEY", PRIVATE_KEY);
|
||||
|
||||
client.init(
|
||||
{
|
||||
@@ -206,7 +211,7 @@ export default function SignUp() {
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
organizationName: firstName + '\'s organization',
|
||||
organizationName: firstName + "'s organization",
|
||||
publicKey: PUBLIC_KEY,
|
||||
ciphertext,
|
||||
iv,
|
||||
@@ -220,10 +225,10 @@ export default function SignUp() {
|
||||
if (response.status === 200) {
|
||||
// response = await response.json();
|
||||
|
||||
localStorage.setItem('publicKey', PUBLIC_KEY);
|
||||
localStorage.setItem('encryptedPrivateKey', ciphertext);
|
||||
localStorage.setItem('iv', iv);
|
||||
localStorage.setItem('tag', tag);
|
||||
localStorage.setItem("publicKey", PUBLIC_KEY);
|
||||
localStorage.setItem("encryptedPrivateKey", ciphertext);
|
||||
localStorage.setItem("iv", iv);
|
||||
localStorage.setItem("tag", tag);
|
||||
|
||||
try {
|
||||
await attemptLogin(
|
||||
@@ -232,16 +237,16 @@ export default function SignUp() {
|
||||
setErrorLogin,
|
||||
router,
|
||||
true,
|
||||
false,
|
||||
false
|
||||
);
|
||||
incrementStep();
|
||||
} catch (error) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
);
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
@@ -284,8 +289,7 @@ export default function SignUp() {
|
||||
</div> */}
|
||||
<div className="flex flex-col items-center justify-center w-5/6 md:w-full md:p-2 max-h-28 max-w-xs md:max-w-md mx-auto mt-4 md:mt-4 text-sm text-center md:text-left">
|
||||
<p className="text-gray-400 mt-2 md:mx-0.5">
|
||||
By creating an account, you agree to our Terms and have read and
|
||||
acknowledged the Privacy Policy.
|
||||
{t("signup:step1-privacy")}
|
||||
</p>
|
||||
<div className="text-l mt-6 m-2 md:m-8 px-8 py-1 text-lg">
|
||||
<Button text="Get Started" type="submit" onButtonPressed={emailCheck} size="lg" />
|
||||
@@ -296,7 +300,7 @@ export default function SignUp() {
|
||||
<Link href="/login">
|
||||
<button type="button" className="w-max pb-3 hover:opacity-90 duration-200">
|
||||
<u className="font-normal text-sm text-primary-500">
|
||||
Have an account? Log in
|
||||
{t("signup:already-have-account")}
|
||||
</u>
|
||||
</button>
|
||||
</Link>
|
||||
@@ -309,10 +313,10 @@ export default function SignUp() {
|
||||
const step2 = (
|
||||
<div className="bg-bunker w-max mx-auto h-7/12 pt-10 pb-4 px-8 rounded-xl drop-shadow-xl mb-64 md:mb-16">
|
||||
<p className="text-l flex justify-center text-gray-400">
|
||||
{'We\'ve'} sent a verification email to{' '}
|
||||
{"We've"} sent a verification email to{" "}
|
||||
</p>
|
||||
<p className="text-l flex justify-center font-semibold my-2 text-gray-400">
|
||||
{email}{' '}
|
||||
{email}{" "}
|
||||
</p>
|
||||
<div className="hidden md:block">
|
||||
<ReactCodeInput
|
||||
@@ -336,11 +340,13 @@ export default function SignUp() {
|
||||
className="mt-2 mb-6"
|
||||
/>
|
||||
</div>
|
||||
{codeError && (
|
||||
<Error text="Oops. Your code is wrong. Please try again." />
|
||||
)}
|
||||
{codeError && <Error text={t("signup:step2-code-error")} />}
|
||||
<div className="flex max-w-min flex-col items-center justify-center md:p-2 max-h-24 max-w-md mx-auto text-lg px-4 mt-4 mb-2">
|
||||
<Button text="Verify" onButtonPressed={incrementStep} size="lg" />
|
||||
<Button
|
||||
text={t("signup:verify") ?? ""}
|
||||
onButtonPressed={incrementStep}
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center w-full max-h-24 max-w-md mx-auto pt-2">
|
||||
<div className="flex flex-row items-baseline gap-1 text-sm">
|
||||
@@ -349,12 +355,12 @@ export default function SignUp() {
|
||||
</span>
|
||||
<u className={`font-normal ${isResendingVerificationEmail ? 'text-gray-400' : 'text-primary-500 hover:opacity-90 duration-200'}`}>
|
||||
<button disabled={isLoading} onClick={resendVerificationEmail}>
|
||||
{isResendingVerificationEmail ? 'Resending...' : 'Resend'}
|
||||
{isResendingVerificationEmail ? "Resending..." : "Resend"}
|
||||
</button>
|
||||
</u>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500 pb-2">
|
||||
Make sure to check your spam inbox.
|
||||
{t("signup:step2-spam-alert")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -364,35 +370,43 @@ export default function SignUp() {
|
||||
const step3 = (
|
||||
<div className="bg-bunker w-max mx-auto h-7/12 py-10 px-8 rounded-xl drop-shadow-xl mb-36 md:mb-16">
|
||||
<p className="text-4xl font-bold flex justify-center mb-6 text-gray-400 mx-8 md:mx-16 text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
||||
Almost there!
|
||||
{t("signup:step3-message")}
|
||||
</p>
|
||||
<div className="relative z-0 flex items-center justify-end w-full md:p-2 rounded-lg max-h-24">
|
||||
<InputField
|
||||
label="First Name"
|
||||
label={t("common:first-name")}
|
||||
onChangeHandler={setFirstName}
|
||||
type="name"
|
||||
value={firstName}
|
||||
isRequired
|
||||
errorText="Please input your first name."
|
||||
errorText={
|
||||
t("common:validate-required", {
|
||||
name: t("common:first-name"),
|
||||
}) as string
|
||||
}
|
||||
error={firstNameError}
|
||||
autoComplete="given-name"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 flex items-center justify-center w-full md:p-2 rounded-lg max-h-24">
|
||||
<InputField
|
||||
label="Last Name"
|
||||
label={t("common:last-name")}
|
||||
onChangeHandler={setLastName}
|
||||
type="name"
|
||||
value={lastName}
|
||||
isRequired
|
||||
errorText="Please input your last name."
|
||||
errorText={
|
||||
t("common:validate-required", {
|
||||
name: t("common:last-name"),
|
||||
}) as string
|
||||
}
|
||||
error={lastNameError}
|
||||
autoComplete="family-name"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-col items-center justify-center w-full md:p-2 rounded-lg max-h-60">
|
||||
<InputField
|
||||
label="Password"
|
||||
label={t("section-password:password")}
|
||||
onChangeHandler={(password: string) => {
|
||||
setPassword(password);
|
||||
passwordCheck({
|
||||
@@ -417,7 +431,7 @@ export default function SignUp() {
|
||||
passwordErrorNumber ? (
|
||||
<div className="w-full mt-4 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md">
|
||||
<div className={`text-gray-400 text-sm mb-1`}>
|
||||
Password should contain at least:
|
||||
{t("section-password:validate-base")}
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
{passwordErrorLength ? (
|
||||
@@ -433,10 +447,10 @@ export default function SignUp() {
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLength ? 'text-gray-400' : 'text-gray-600'
|
||||
passwordErrorLength ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
14 characters
|
||||
{t("section-password:validate-length")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -453,10 +467,10 @@ export default function SignUp() {
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'
|
||||
passwordErrorLowerCase ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 lowercase character
|
||||
{t("section-password:validate-case")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
@@ -473,10 +487,10 @@ export default function SignUp() {
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorNumber ? 'text-gray-400' : 'text-gray-600'
|
||||
passwordErrorNumber ? "text-gray-400" : "text-gray-600"
|
||||
} text-sm`}
|
||||
>
|
||||
1 number
|
||||
{t("section-password:validate-number")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -486,7 +500,7 @@ export default function SignUp() {
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center md:p-2 max-h-48 max-w-max mx-auto text-lg px-2 py-3">
|
||||
<Button
|
||||
text="Sign Up"
|
||||
text={t("signup:signup") ?? ""}
|
||||
loading={isLoading}
|
||||
onButtonPressed={signupErrorCheck}
|
||||
size="lg"
|
||||
@@ -499,21 +513,15 @@ export default function SignUp() {
|
||||
const step4 = (
|
||||
<div className="bg-bunker flex flex-col items-center w-full max-w-xs md:max-w-lg mx-auto h-7/12 py-8 px-4 md:px-6 mx-1 mb-36 md:mb-16 rounded-xl drop-shadow-xl">
|
||||
<p className="text-4xl text-center font-semibold flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
||||
Save your Emergency Kit
|
||||
{t("signup:step4-message")}
|
||||
</p>
|
||||
<div className="flex flex-col items-center justify-center w-full mt-4 md:mt-8 max-w-md text-gray-400 text-md rounded-md px-2">
|
||||
<div>
|
||||
If you get locked out of your account, your Emergency Kit is the only
|
||||
way to sign in.
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
We recommend you download it and keep it somewhere safe.
|
||||
</div>
|
||||
<div>{t("signup:step4-description1")}</div>
|
||||
<div className="mt-3">{t("signup:step4-description2")}</div>
|
||||
</div>
|
||||
<div className="w-full p-2 flex flex-row items-center bg-white/10 text-gray-400 rounded-md max-w-xs md:max-w-md mx-auto mt-4">
|
||||
<FontAwesomeIcon icon={faWarning} className="ml-2 mr-4 text-4xl" />
|
||||
It contains your Secret Key which we cannot access or recover for you if
|
||||
you lose it.
|
||||
{t("signup:step4-description3")}
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center md:px-4 md:py-5 mt-2 px-2 py-3 max-h-24 max-w-max mx-auto text-lg">
|
||||
<Button
|
||||
@@ -522,11 +530,13 @@ export default function SignUp() {
|
||||
await issueBackupKey({
|
||||
email,
|
||||
password,
|
||||
personalName: firstName + ' ' + lastName,
|
||||
personalName: firstName + " " + lastName,
|
||||
setBackupKeyError,
|
||||
setBackupKeyIssued
|
||||
setBackupKeyIssued,
|
||||
});
|
||||
router.push('/dashboard/');
|
||||
const userWorkspaces = await getWorkspaces();
|
||||
const userWorkspace = userWorkspaces[0]._id;
|
||||
router.push("/home/" + userWorkspace);
|
||||
}}
|
||||
size="lg"
|
||||
/>
|
||||
@@ -549,16 +559,13 @@ export default function SignUp() {
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col items-center justify-center">
|
||||
<Head>
|
||||
<title>Infiscal | Sign Up</title>
|
||||
<title>{t("common:head-title", { title: t("signup:title") })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes."
|
||||
/>
|
||||
<meta property="og:title" content={t("signup:og-title") as string} />
|
||||
<meta
|
||||
name="og:description"
|
||||
content="Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js..."
|
||||
content={t("signup:og-description") as string}
|
||||
/>
|
||||
</Head>
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
@@ -579,3 +586,9 @@ export default function SignUp() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = getTranslatedStaticProps([
|
||||
"auth",
|
||||
"signup",
|
||||
"section-password",
|
||||
]);
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import { faMagnifyingGlass, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { useEffect, useState } from "react";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/router";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { faMagnifyingGlass, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import AddProjectMemberDialog from '~/components/basic/dialog/AddProjectMemberDialog';
|
||||
import UserTable from '~/components/basic/table/UserTable';
|
||||
import NavHeader from '~/components/navigation/NavHeader';
|
||||
import guidGenerator from '~/utilities/randomId';
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import AddProjectMemberDialog from "~/components/basic/dialog/AddProjectMemberDialog";
|
||||
import UserTable from "~/components/basic/table/UserTable";
|
||||
import NavHeader from "~/components/navigation/NavHeader";
|
||||
import guidGenerator from "~/utilities/randomId";
|
||||
import { getTranslatedServerSideProps } from "~/utilities/withTranslateProps";
|
||||
|
||||
import getOrganizationUsers from '../api/organization/GetOrgUsers';
|
||||
import getUser from '../api/user/getUser';
|
||||
@@ -35,6 +37,8 @@ export default function Users() {
|
||||
const [personalEmail, setPersonalEmail] = useState('');
|
||||
const [searchUsers, setSearchUsers] = useState('');
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
let workspaceId;
|
||||
|
||||
@@ -124,14 +128,21 @@ export default function Users() {
|
||||
return userList ? (
|
||||
<div className="bg-bunker-800 md:h-screen flex flex-col justify-start">
|
||||
<Head>
|
||||
<title>Users</title>
|
||||
<title>
|
||||
{t("common:head-title", { title: t("settings-members:title") })}
|
||||
</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<NavHeader pageName="Project Members" isProjectRelated={true} />
|
||||
<NavHeader
|
||||
pageName={t("settings-members:title")}
|
||||
isProjectRelated={true}
|
||||
/>
|
||||
<div className="flex flex-col justify-start items-start px-6 py-6 pb-4 text-3xl">
|
||||
<p className="font-semibold mr-4 text-white">Project Members</p>
|
||||
<p className="font-semibold mr-4 text-white">
|
||||
{t("settings-members:title")}
|
||||
</p>
|
||||
<p className="mr-4 text-base text-gray-400">
|
||||
This pages shows the members of the selected project.
|
||||
{t("settings-members:description")}
|
||||
</p>
|
||||
</div>
|
||||
<AddProjectMemberDialog
|
||||
@@ -159,12 +170,12 @@ export default function Users() {
|
||||
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
|
||||
value={searchUsers}
|
||||
onChange={(e) => setSearchUsers(e.target.value)}
|
||||
placeholder={'Search members...'}
|
||||
placeholder={t("section-members:search-members")}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 ml-2 min-w-max flex flex-row items-start justify-start mr-4">
|
||||
<Button
|
||||
text="Add Member"
|
||||
text={t("section-members:add-member")}
|
||||
onButtonPressed={openAddModal}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -201,3 +212,9 @@ export default function Users() {
|
||||
}
|
||||
|
||||
Users.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
"settings",
|
||||
"settings-members",
|
||||
"section-members",
|
||||
]);
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { useState } from 'react';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useState } from "react";
|
||||
import Head from "next/head";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import Button from '~/components/basic/buttons/Button';
|
||||
import InputField from '~/components/basic/InputField';
|
||||
import Button from "~/components/basic/buttons/Button";
|
||||
import InputField from "~/components/basic/InputField";
|
||||
import { getTranslatedStaticProps } from "~/components/utilities/withTranslateProps";
|
||||
|
||||
import SendEmailOnPasswordReset from './api/auth/SendEmailOnPasswordReset';
|
||||
import SendEmailOnPasswordReset from "./api/auth/SendEmailOnPasswordReset";
|
||||
|
||||
export default function VerifyEmail() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [email, setEmail] = useState("");
|
||||
const [step, setStep] = useState(1);
|
||||
|
||||
/**
|
||||
@@ -92,3 +93,5 @@ export default function VerifyEmail() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = getTranslatedStaticProps([]);
|
||||
|
||||
28
frontend/public/locales/en/billing.json
Normal file
28
frontend/public/locales/en/billing.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"title": "Usage & Billing",
|
||||
"description": "View and manage your organization's subscription here",
|
||||
"subscription": "Subscription",
|
||||
"starter": {
|
||||
"name": "Starter",
|
||||
"price-explanation": "up to 5 team members",
|
||||
"text": "Manage any project with 5 members for free!",
|
||||
"subtext": "$5 per member/month afterwards."
|
||||
},
|
||||
"professional": {
|
||||
"name": "Professional",
|
||||
"price-explanation": "/member/month",
|
||||
"subtext": "Includes unlimited projects & members.",
|
||||
"text": "Keep up with key management as you grow."
|
||||
},
|
||||
"enterprise": {
|
||||
"name": "Enterprise",
|
||||
"text": "Keep up with key management as you grow."
|
||||
},
|
||||
"current-usage": "Current Usage",
|
||||
"free": "Free",
|
||||
"downgrade": "Downgrade",
|
||||
"upgrade": "Upgrade",
|
||||
"learn-more": "Learn More",
|
||||
"custom-pricing": "Custom Pricing",
|
||||
"schedule-demo": "Schedule a Demo"
|
||||
}
|
||||
26
frontend/public/locales/en/common.json
Normal file
26
frontend/public/locales/en/common.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"head-title": "{{title}} | Infiscal",
|
||||
"error_project-already-exists": "A project with this name already exists.",
|
||||
"no-mobile": " To use Infisical, please log in through a device with larger dimensions. ",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"first-name": "First Name",
|
||||
"last-name": "Last Name",
|
||||
"logout": "Log Out",
|
||||
"validate-required": "Please input your {{name}}",
|
||||
|
||||
"maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.",
|
||||
"click-to-copy": "Click to copy",
|
||||
"project-id": "Project ID",
|
||||
"save-changes": "Save Changes",
|
||||
"saved": "Saved",
|
||||
"drop-zone": "Drag and drop your .env file here.",
|
||||
"drop-zone-keys": "Drag and drop your .env file here to add more keys.",
|
||||
"role": "Role",
|
||||
"role_admin": "admin",
|
||||
"display-name": "Display Name",
|
||||
"environment": "Environment",
|
||||
"expired-in": "Expires in",
|
||||
"language": "Language",
|
||||
"search": "Search..."
|
||||
}
|
||||
19
frontend/public/locales/en/dashboard.json
Normal file
19
frontend/public/locales/en/dashboard.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"title": "Secrets",
|
||||
"og-title": "Manage your .env files in seconds",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.",
|
||||
"search-keys": "Search keys...",
|
||||
"add-key": "Add Key",
|
||||
"personal": "Personal",
|
||||
"personal-description": "Personal keys are only visible to you",
|
||||
"shared": "Shared",
|
||||
"shared-description": "Shared keys are visible to your whole team",
|
||||
"make-shared": "Make Shared",
|
||||
"make-personal": "Make Personal",
|
||||
"check-docs": {
|
||||
"button": "Check Docs",
|
||||
"title": "Good job!",
|
||||
"line1": "Congrats on adding more secrets.",
|
||||
"line2": "Here is how to connect them to your codebase."
|
||||
}
|
||||
}
|
||||
9
frontend/public/locales/en/integrations.json
Normal file
9
frontend/public/locales/en/integrations.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"title": "Project Integrations",
|
||||
"description": "Manage your integrations of Infisical with third-party services.",
|
||||
"no-integrations1": "You don't have any integrations set up yet. When you do, they will appear here.",
|
||||
"no-integrations2": "To start, click on any of the options below. It takes 5 clicks to set up.",
|
||||
"available": "Platform & Cloud Integrations",
|
||||
"available-text1": "Click on the itegration you want to connect. This will let your environment variables flow automatically into selected third-party services.",
|
||||
"available-text2": " Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com."
|
||||
}
|
||||
8
frontend/public/locales/en/login.json
Normal file
8
frontend/public/locales/en/login.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "Login",
|
||||
"og-title": "Log In to Infisical",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.",
|
||||
"login": "Log In",
|
||||
"need-account": "Need an Infisical account?",
|
||||
"create-account": "Create an account"
|
||||
}
|
||||
22
frontend/public/locales/en/nav.json
Normal file
22
frontend/public/locales/en/nav.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"support": {
|
||||
"slack": "[NEW] Join Slack Forum",
|
||||
"docs": "Read Docs",
|
||||
"issue": "Open a Github Issue",
|
||||
"email": "Send us an Email"
|
||||
},
|
||||
"user": {
|
||||
"signed-in-as": "SIGNED IN AS",
|
||||
"current-organization": "CURRENT ORGANIZATION",
|
||||
"usage-billing": "Usage & Billing",
|
||||
"invite": "Invite Members",
|
||||
"other-organizations": "OTHER ORGANIZATION"
|
||||
},
|
||||
"menu": {
|
||||
"project": "PROJECT",
|
||||
"secrets": "Secrets",
|
||||
"members": "Members",
|
||||
"integrations": "Integrations",
|
||||
"project-settings": "Project Settings"
|
||||
}
|
||||
}
|
||||
11
frontend/public/locales/en/section-incident.json
Normal file
11
frontend/public/locales/en/section-incident.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"incident-contacts": "Incident Contacts",
|
||||
"incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.",
|
||||
"no-incident-contacts": "No incident contacts found.",
|
||||
"add-contact": "Add Contact",
|
||||
"add-dialog": {
|
||||
"title": "Add an Incident Contact",
|
||||
"description": "This contact will be notified in the unlikely event of a severe incident.",
|
||||
"add-incident": "Add Incident Contact"
|
||||
}
|
||||
}
|
||||
14
frontend/public/locales/en/section-members.json
Normal file
14
frontend/public/locales/en/section-members.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"add-member": "Add Member",
|
||||
"org-members": "Organization Members",
|
||||
"org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.",
|
||||
"search-members": "Search members...",
|
||||
"add-dialog": {
|
||||
"add-member-to-project": "Add a member to your project",
|
||||
"already-all-invited": "All the users in your organization are already invited.",
|
||||
"add-user-org-first": "Add more users to the organization first.",
|
||||
"user-will-email": "The user will receive an email with the instructions.",
|
||||
"looking-add": "<0>If you are looking to add users to your org,</0><1>click here</1>",
|
||||
"add-user-to-org": "Add Users to Organization"
|
||||
}
|
||||
}
|
||||
11
frontend/public/locales/en/section-password.json
Normal file
11
frontend/public/locales/en/section-password.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"password": "Password",
|
||||
"change": "Change password",
|
||||
"current": "Current password",
|
||||
"current-wrong": "The current password may be wrong",
|
||||
"new": "New password",
|
||||
"validate-base": "Password should contain at least:",
|
||||
"validate-length": "14 characters",
|
||||
"validate-case": "1 lowercase character",
|
||||
"validate-number": "1 number"
|
||||
}
|
||||
13
frontend/public/locales/en/section-token.json
Normal file
13
frontend/public/locales/en/section-token.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"service-tokens": "Service Tokens",
|
||||
"service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project.",
|
||||
"add-new": "Add New Token",
|
||||
"add-dialog": {
|
||||
"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.",
|
||||
"name": "Service Token Name",
|
||||
"add": "Add Service Token",
|
||||
"copy-service-token": "Copy your service token",
|
||||
"copy-service-token-description": "Once you close this popup, you will never see your service token again"
|
||||
}
|
||||
}
|
||||
4
frontend/public/locales/en/settings-members.json
Normal file
4
frontend/public/locales/en/settings-members.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Project Members",
|
||||
"description": "This pages shows the members of the selected project."
|
||||
}
|
||||
4
frontend/public/locales/en/settings-org.json
Normal file
4
frontend/public/locales/en/settings-org.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "Organization Settings",
|
||||
"description": "Manage members of your organization. These users could afterwards be formed into projects."
|
||||
}
|
||||
11
frontend/public/locales/en/settings-personal.json
Normal file
11
frontend/public/locales/en/settings-personal.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"title": "Personal Settings",
|
||||
"description": "View and manage your personal information here.",
|
||||
"emergency": {
|
||||
"name": "Emergency Kit",
|
||||
"text1": "Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.",
|
||||
"text2": "Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.",
|
||||
"download": "Download Emergency Kit"
|
||||
},
|
||||
"change-language": "Change Language"
|
||||
}
|
||||
13
frontend/public/locales/en/settings-project.json
Normal file
13
frontend/public/locales/en/settings-project.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"title": "Project Settings",
|
||||
"description": "These settings only apply to the currently selected Project.",
|
||||
"danger-zone": "Danger Zone",
|
||||
"delete-project": "Delete Project",
|
||||
"project-to-delete": "Project to be Deleted",
|
||||
"danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.",
|
||||
"delete-project-note": "Note: You can only delete a project in case you have more than one",
|
||||
"project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.",
|
||||
"project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ",
|
||||
"auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.",
|
||||
"docs": "Infisical Docs"
|
||||
}
|
||||
21
frontend/public/locales/en/signup.json
Normal file
21
frontend/public/locales/en/signup.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"title": "Sign Up",
|
||||
"og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...",
|
||||
"signup": "Sign Up",
|
||||
"already-have-account": "Have an account? Log in",
|
||||
"forgot-password": "Forgot your password?",
|
||||
"verify": "Verify",
|
||||
"step1-start": "Let's get started",
|
||||
"step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.",
|
||||
"step1-submit": "Get Started",
|
||||
"step2-message": "<wrapper>We've sent a verification email to</wrapper><email>{{email}}</email>",
|
||||
"step2-code-error": "Oops. Your code is wrong. Please try again.",
|
||||
"step2-spam-alert": "Make sure to check your spam inbox.",
|
||||
"step3-message": "Almost there!",
|
||||
"step4-message": "Save your Emergency Kit",
|
||||
"step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.",
|
||||
"step4-description2": "We recommend you download it and keep it somewhere safe.",
|
||||
"step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.",
|
||||
"step4-download": "Download PDF"
|
||||
}
|
||||
28
frontend/public/locales/ko/billing.json
Normal file
28
frontend/public/locales/ko/billing.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"title": "요금제 & 결제",
|
||||
"description": "이곳에서 조직의 구독을 확인하고 관리할 수 있어요.",
|
||||
"subscription": "구독",
|
||||
"starter": {
|
||||
"name": "스타터",
|
||||
"price-explanation": "5명의 팀 맴버까지",
|
||||
"text": "어떤 프로젝트든 다섯명의 맴버까지 무료로 이용할 수 있어요!",
|
||||
"subtext": "$5명/달 로 바뀔 예정입니다."
|
||||
},
|
||||
"professional": {
|
||||
"name": "전문가",
|
||||
"price-explanation": "/맴버/달",
|
||||
"subtext": "무제한의 프로젝트와 맴버",
|
||||
"text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요."
|
||||
},
|
||||
"enterprise": {
|
||||
"name": "엔터프라이즈",
|
||||
"text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요."
|
||||
},
|
||||
"current-usage": "현재 요금제",
|
||||
"free": "무료",
|
||||
"downgrade": "다운그레이드",
|
||||
"upgrade": "업그레이드",
|
||||
"learn-more": "자세히 알아보기",
|
||||
"custom-pricing": "커스텀 가격",
|
||||
"schedule-demo": "데모 예약하기"
|
||||
}
|
||||
26
frontend/public/locales/ko/common.json
Normal file
26
frontend/public/locales/ko/common.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"head-title": "{{title}} | Infiscal",
|
||||
"error_project-already-exists": "동일한 이름을 가진 프로젝트가 이미 존재해요.",
|
||||
"no-mobile": " Infisical을 사용하려면, 큰 화면을 가진 디바이스로 로그인하여 주세요.",
|
||||
"email": "메일",
|
||||
"password": "비밀번호",
|
||||
"first-name": "이름",
|
||||
"last-name": "성",
|
||||
"logout": "로그아웃",
|
||||
"validate-required": "{{name}} 을/를 입력하세요.",
|
||||
"maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.",
|
||||
"click-to-copy": "클릭하여 복사하기",
|
||||
"project-id": "프로젝트 ID",
|
||||
"save-changes": "변경사항 저장하기",
|
||||
"saved": "저장됨",
|
||||
"drop-zone": ".env 파일을 이곳에 드래그 & 드롭 하세요.",
|
||||
"drop-zone-keys": "이곳에 .env 파일을 드래그 & 드롭 하여 더 많은 키들을 추가하세요.",
|
||||
"role": "Role",
|
||||
"role_admin": "admin",
|
||||
"display-name": "표시 이름",
|
||||
|
||||
"environment": "환경",
|
||||
"expired-in": "만료 기한:",
|
||||
"language": "언어",
|
||||
"search": "검색하기..."
|
||||
}
|
||||
19
frontend/public/locales/ko/dashboard.json
Normal file
19
frontend/public/locales/ko/dashboard.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"title": "시크릿",
|
||||
"og-title": "빠르게 .env 파일을 관리하세요",
|
||||
"og-description": "Infisical은 팀원과 .env파일을 공유할 수 있는 심플한 end-to-end 암호화 플렛폼입니다.",
|
||||
"search-keys": "키 검색하기...",
|
||||
"add-key": "키 추가하기",
|
||||
"personal": "개인",
|
||||
"personal-description": "개인 키는 오직 본인만 볼 수 있어요",
|
||||
"shared": "공유",
|
||||
"shared-description": "공유 키는 팀 전체가 볼 수 있어요",
|
||||
"make-shared": "공유로 만들기",
|
||||
"make-personal": "개인으로 만들기",
|
||||
"check-docs": {
|
||||
"button": "문서 확인하기",
|
||||
"title": "좋았어요!",
|
||||
"line1": "더 많은 시크릿들을 추가한 것을 축하합니다.",
|
||||
"line2": "코드와 연결하는 사용하는 방법을 한번 알아보지 않을래요?"
|
||||
}
|
||||
}
|
||||
9
frontend/public/locales/ko/integrations.json
Normal file
9
frontend/public/locales/ko/integrations.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"available": "사용 가능한 연동",
|
||||
"available-text1": "연결하고 싶은 서비스를 클릭하세요. 환경 변수가 선택한 외부 서비스와 자동으로 연동됩니다.",
|
||||
"available-text2": "참고: Heroku와의 연동에서는 보안상의 이유로 End-To-End 암호화를 유지하는 것이 불가능합니다. 이론적으로는 Infisical이 시크릿을 읽는것이 가능하지만, 절대 그러지 않는다고 확신할 수 있습니다. 핵심 Infisical 서비스는 항상 End-To-End 암호화 상태를 유지합니다. 질문이 있으면 support@infisical.com으로 문의하세요.",
|
||||
"description": "외부 서비스와 함께 Infisical을 연동하고 관리하세요",
|
||||
"no-integrations1": "연동된 서비스가 없어요. 연동하게 된다면 이곳에서 표시돼요.",
|
||||
"no-integrations2": "시작하려면, 아래의 옵션을 클릭하세요. 대체로 5분 이내로 가능해요.",
|
||||
"title": "프로젝트 연동"
|
||||
}
|
||||
8
frontend/public/locales/ko/login.json
Normal file
8
frontend/public/locales/ko/login.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "로그인",
|
||||
"og-title": "Infisical에 로그인하기",
|
||||
"og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.",
|
||||
"login": "로그인",
|
||||
"need-account": "Infisical계정이 필요하신가요?",
|
||||
"create-account": "회원가입 하기"
|
||||
}
|
||||
22
frontend/public/locales/ko/nav.json
Normal file
22
frontend/public/locales/ko/nav.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"support": {
|
||||
"slack": "[NEW] 슬랙 포럼에 가입하기",
|
||||
"docs": "문서 보기",
|
||||
"issue": "깃허브 이슈 열기",
|
||||
"email": "Infisical팀에게 메일 보내기"
|
||||
},
|
||||
"user": {
|
||||
"signed-in-as": "다음으로 로그인됨",
|
||||
"current-organization": "현재 조직",
|
||||
"usage-billing": "요금제 & 결제",
|
||||
"invite": "맴버 초대하기",
|
||||
"other-organizations": "다른 조직"
|
||||
},
|
||||
"menu": {
|
||||
"project": "프로젝트",
|
||||
"secrets": "시크릿",
|
||||
"members": "맴버",
|
||||
"integrations": "연동",
|
||||
"project-settings": "프로젝트 설정"
|
||||
}
|
||||
}
|
||||
11
frontend/public/locales/ko/section-incident.json
Normal file
11
frontend/public/locales/ko/section-incident.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"add-contact": "연락처 추가하기",
|
||||
"add-dialog": {
|
||||
"add-incident": "비상 연락처 추가하기",
|
||||
"description": "중대한 일이 생길 경우, 이 연락처로 알림이 전송됩니다.",
|
||||
"title": "비상 연락처 추가하기"
|
||||
},
|
||||
"incident-contacts": "비상 연락망",
|
||||
"incident-contacts-description": "중대한 일이 생길 경우, 아래의 연락처로 알림이 전송됩니다.",
|
||||
"no-incident-contacts": "비상 연락망이 존재하지 않아요."
|
||||
}
|
||||
14
frontend/public/locales/ko/section-members.json
Normal file
14
frontend/public/locales/ko/section-members.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"add-member": "맴버 추가하기",
|
||||
"org-members": "조직 맴버",
|
||||
"search-members": "맴버를 검색하기...",
|
||||
"add-dialog": {
|
||||
"add-member-to-project": "프로젝트에 맴버 추가하기",
|
||||
"already-all-invited": "조직의 모든 유저가 이미 초대되었습니다.",
|
||||
"add-user-org-first": "유저를 먼저 조직에 추가해 주세요.",
|
||||
"user-will-email": "유저는 안내가 포함된 메일을 받게 됩니다.",
|
||||
"looking-add": "<0>조직에 유저를 추가하고 싶다면,</0><1>여기를 클릭하세요</1>",
|
||||
"add-user-to-org": "조직에 유저 추가하기"
|
||||
},
|
||||
"org-members-description": "조직의 맴버들을 관리하세요."
|
||||
}
|
||||
11
frontend/public/locales/ko/section-password.json
Normal file
11
frontend/public/locales/ko/section-password.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"password": "비밀번호",
|
||||
"change": "비밀번호 변경",
|
||||
"current": "현재 비밀번호",
|
||||
"new": "새 비밀번호",
|
||||
"current-wrong": "현재 비밀번호가 잘못되었어요",
|
||||
"validate-base": "비밀번호는 다음 조건을 만족해야 합니다:",
|
||||
"validate-length": "14 글자 이상",
|
||||
"validate-case": "1개 이상의 소문자",
|
||||
"validate-number": "1개 이상의 숫자"
|
||||
}
|
||||
13
frontend/public/locales/ko/section-token.json
Normal file
13
frontend/public/locales/ko/section-token.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"add-dialog": {
|
||||
"add": "서비스 토큰 추가하기",
|
||||
"copy-service-token": "서비스 토큰 복사하기",
|
||||
"copy-service-token-description": "팝업을 닫을 시 다시는 토큰을 확인할 수 없어요.",
|
||||
"description": "이름, 환경, 만료일을 지정하세요. 토큰이 생성되면 최초 한번만 볼 수 있어요. 안전한 곳에 저장하세요.",
|
||||
"name": "서비스 토큰 이름",
|
||||
"title": "{{target}}의 토큰 추가하기"
|
||||
},
|
||||
"add-new": "새 토큰 추가하기",
|
||||
"service-tokens": "서비스 토큰",
|
||||
"service-tokens-description": "모든 서비스 토큰은 프로젝트 및 환경에 따라 다릅니다."
|
||||
}
|
||||
4
frontend/public/locales/ko/settings-members.json
Normal file
4
frontend/public/locales/ko/settings-members.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "맴버 설정",
|
||||
"description": "선택한 프로젝트의 맴버를 확인하세요."
|
||||
}
|
||||
4
frontend/public/locales/ko/settings-org.json
Normal file
4
frontend/public/locales/ko/settings-org.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "조직 설정",
|
||||
"description": "조직의 맴버를 관리하세요."
|
||||
}
|
||||
11
frontend/public/locales/ko/settings-personal.json
Normal file
11
frontend/public/locales/ko/settings-personal.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"title": "개인 설정",
|
||||
"description": "계정 및 기본적인 설정을 확인하고 변경하세요.",
|
||||
"emergency": {
|
||||
"name": "긴급복구 키트",
|
||||
"text1": "긴급복구 키트는 Infisical계정에 로그인 할 수 있는 정보를 가지고 있어요.",
|
||||
"text2": "오직 마지막으로 발급한 긴급복구 키트만 사용 가능해요. 새로운 긴급복구 키트를 받으려면, 비밀번호를 입력하세요.",
|
||||
"download": "긴급복구 키트 다운로드"
|
||||
},
|
||||
"change-language": "언어 변경하기"
|
||||
}
|
||||
13
frontend/public/locales/ko/settings-project.json
Normal file
13
frontend/public/locales/ko/settings-project.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"title": "프로젝트 설정",
|
||||
"description": "현재 선택한 프로젝트에 대해서 설정해요.",
|
||||
"auto-generated": "자동으로 생성된 고유한 키 입니다. 변경할 수 없어요.",
|
||||
"danger-zone": "위험존",
|
||||
"danger-zone-note": "프로젝트를 삭제한다면 모든 키가 즉시 삭제되며 다시는 되돌릴 수 없어요. 삭제를 원한다면 프로젝트 이름을 아래에 적어주세요.",
|
||||
"delete-project": "프로젝트 삭제",
|
||||
"delete-project-note": "노트: 최소 한개 이상의 프로젝트는 조직에 존재해야 해요.",
|
||||
"docs": "Infisical 문서",
|
||||
"project-id-description": "다른 코드에서 Infisical과 환경변수를 연동하기 위해서는 프로젝트 ID가 필요해요.",
|
||||
"project-id-description2": "다양한 언어 및 프레임워크에 대한 가이드를 확인하고 싶다면, 다음을 확인하세요. ",
|
||||
"project-to-delete": "삭제할 프로젝트"
|
||||
}
|
||||
21
frontend/public/locales/ko/signup.json
Normal file
21
frontend/public/locales/ko/signup.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"title": "회원가입",
|
||||
"og-title": "한줄의 코드르 .env파일을 교체하세요. 3분이면 가입할 수 있어요.",
|
||||
"og-description": "Infisical은 팀원과 .env파일을 공유하고 연동할 수 있는 심플한 end-to-end 암호화 플렛폼입니다. Node.js, Next.js, Gatsby, Nest.js 와 같은 다양한 플렛폼에서 작동해요.",
|
||||
"signup": "회원가입",
|
||||
"already-have-account": "이미 계정이 있나요? 로그인하기",
|
||||
"forgot-password": "비밀번호를 잊으셨나요?",
|
||||
"verify": "인증",
|
||||
"step1-start": "시작하기",
|
||||
"step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.",
|
||||
"step1-submit": "시작하기",
|
||||
"step2-message": "<email>{{email}}</email><wrapper>로 인증 메일을 전송하였습니다</wrapper><email>{{email}}</email>",
|
||||
"step2-code-error": "코드가 잘못된 것 같아요. 다시 시도해주세요.",
|
||||
"step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요",
|
||||
"step3-message": "거의다 끝났어요!",
|
||||
"step4-message": "긴급복구 키트 저장하기",
|
||||
"step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.",
|
||||
"step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.",
|
||||
"step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.",
|
||||
"step4-download": "PDF 다운로드"
|
||||
}
|
||||
Reference in New Issue
Block a user