Merge branch 'main' into feature/ldap-gateway-support
@@ -150,7 +150,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz",
|
||||
"integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
@@ -195,7 +196,6 @@
|
||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.3",
|
||||
@@ -488,7 +488,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@casl/ability/-/ability-6.7.2.tgz",
|
||||
"integrity": "sha512-KjKXlcjKbUz8dKw7PY56F7qlfOFgxTU6tnlJ8YrbDyWkJMIlHa6VRWzCD8RU20zbJUC1hExhOFggZjm6tf1mUw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ucast/mongo2js": "^1.3.0"
|
||||
},
|
||||
@@ -547,7 +546,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@dnd-kit/accessibility": "^3.1.1",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
@@ -1325,7 +1323,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.1.tgz",
|
||||
"integrity": "sha512-8dBIHbfsKlCk2jHQ9PoRBg2Z+4TwyE3vZICSnoDlnsHA6SiMlTwfmW6yX0lHsRmWJugkeb92sA0hZdkXJhuz+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-common-types": "6.7.1"
|
||||
},
|
||||
@@ -2016,7 +2013,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.2.tgz",
|
||||
"integrity": "sha512-hEb7Ma4cGJGEUNOAVmyfdB/3WirWMg5hDuNFVejGEDFqupeOysLc2sG6HJxY2etBp5YQu5Wtxwi020jS9xlUwg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.0.0",
|
||||
@@ -4412,7 +4408,6 @@
|
||||
"integrity": "sha512-RnO1SaiCFHn666wNz2QfZEFxvmiNRqhzaMXHXxXXKt+MEP7aajlPxUSMIQpKAaJfverpovEYqjBOXDq6dDcaOQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/utils": "^8.13.0",
|
||||
"eslint-visitor-keys": "^4.2.0",
|
||||
@@ -5038,7 +5033,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.95.1.tgz",
|
||||
"integrity": "sha512-P5x4yNhcdkYsCEoYeGZP8Q9Jlxf0WXJa4G/xvbmM905seZc9FqJqvCSRvX3dWTPOXRABhl4g+8DHqfft0c/AvQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@tanstack/history": "1.95.0",
|
||||
"@tanstack/react-store": "^0.7.0",
|
||||
@@ -5250,6 +5244,7 @@
|
||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
"@babel/runtime": "^7.12.5",
|
||||
@@ -5270,6 +5265,7 @@
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
@@ -5280,6 +5276,7 @@
|
||||
"integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@adobe/css-tools": "^4.4.0",
|
||||
"aria-query": "^5.0.0",
|
||||
@@ -5299,7 +5296,8 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
|
||||
"integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@testing-library/user-event": {
|
||||
"version": "14.6.1",
|
||||
@@ -5307,6 +5305,7 @@
|
||||
"integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"npm": ">=6"
|
||||
@@ -5327,7 +5326,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
@@ -5380,6 +5380,7 @@
|
||||
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/deep-eql": "*",
|
||||
"assertion-error": "^2.0.1"
|
||||
@@ -5453,7 +5454,8 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
|
||||
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/doctrine": {
|
||||
"version": "0.0.9",
|
||||
@@ -5589,7 +5591,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz",
|
||||
"integrity": "sha512-oh8AMIC4Y2ciKufU8hnKgs+ufgbA/dhPTACaZPM86AbwX9QwnFtSoPWEeRUj8fge+v6kFt78BXcDhAU1SrrAsw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -5601,7 +5602,6 @@
|
||||
"integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
@@ -5649,7 +5649,6 @@
|
||||
"integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
@@ -5690,7 +5689,6 @@
|
||||
"integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.34.0",
|
||||
"@typescript-eslint/types": "8.34.0",
|
||||
@@ -5962,6 +5960,7 @@
|
||||
"integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "3.2.4",
|
||||
@@ -5979,6 +5978,7 @@
|
||||
"integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/spy": "3.2.4",
|
||||
"estree-walker": "^3.0.3",
|
||||
@@ -6006,6 +6006,7 @@
|
||||
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0"
|
||||
}
|
||||
@@ -6016,6 +6017,7 @@
|
||||
"integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tinyrainbow": "^2.0.0"
|
||||
},
|
||||
@@ -6029,6 +6031,7 @@
|
||||
"integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tinyspy": "^4.0.3"
|
||||
},
|
||||
@@ -6042,6 +6045,7 @@
|
||||
"integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "3.2.4",
|
||||
"loupe": "^3.1.4",
|
||||
@@ -6115,7 +6119,6 @@
|
||||
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -6232,6 +6235,7 @@
|
||||
"integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -6280,6 +6284,7 @@
|
||||
"integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -6360,6 +6365,7 @@
|
||||
"integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -6447,6 +6453,7 @@
|
||||
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -6457,6 +6464,7 @@
|
||||
"integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.1"
|
||||
},
|
||||
@@ -6469,7 +6477,8 @@
|
||||
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
|
||||
"integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
@@ -6519,6 +6528,7 @@
|
||||
"integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -6620,6 +6630,7 @@
|
||||
"integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"open": "^8.0.4"
|
||||
},
|
||||
@@ -6856,7 +6867,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.9",
|
||||
"caniuse-lite": "^1.0.30001746",
|
||||
@@ -7038,6 +7048,7 @@
|
||||
"integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"assertion-error": "^2.0.1",
|
||||
"check-error": "^2.1.1",
|
||||
@@ -7108,6 +7119,7 @@
|
||||
"integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
}
|
||||
@@ -7493,7 +7505,8 @@
|
||||
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
||||
"integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cssesc": {
|
||||
"version": "3.0.0",
|
||||
@@ -7512,8 +7525,7 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cva": {
|
||||
"name": "class-variance-authority",
|
||||
@@ -7585,7 +7597,6 @@
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -7639,7 +7650,8 @@
|
||||
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
|
||||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause"
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/data-view-buffer": {
|
||||
"version": "1.0.1",
|
||||
@@ -7749,6 +7761,7 @@
|
||||
"integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
@@ -7783,6 +7796,7 @@
|
||||
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -7904,7 +7918,8 @@
|
||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/dom-helpers": {
|
||||
"version": "5.2.1",
|
||||
@@ -8114,6 +8129,7 @@
|
||||
"integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -8197,7 +8213,6 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
@@ -8239,6 +8254,7 @@
|
||||
"integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
@@ -8275,7 +8291,6 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -8332,7 +8347,6 @@
|
||||
"integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"object.assign": "^4.1.2",
|
||||
@@ -8355,7 +8369,6 @@
|
||||
"integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"confusing-browser-globals": "^1.0.10",
|
||||
"object.assign": "^4.1.2",
|
||||
@@ -8386,7 +8399,6 @@
|
||||
"integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
@@ -8486,7 +8498,6 @@
|
||||
"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.8",
|
||||
@@ -8616,6 +8627,7 @@
|
||||
"integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.8",
|
||||
"array.prototype.findlast": "^1.2.5",
|
||||
@@ -8649,7 +8661,6 @@
|
||||
"integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -8673,6 +8684,7 @@
|
||||
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
@@ -8686,6 +8698,7 @@
|
||||
"integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
"path-parse": "^1.0.7",
|
||||
@@ -8704,6 +8717,7 @@
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
@@ -8865,6 +8879,7 @@
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
@@ -9895,7 +9910,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.2"
|
||||
},
|
||||
@@ -9989,6 +10003,7 @@
|
||||
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -10265,6 +10280,7 @@
|
||||
"integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"is-docker": "cli.js"
|
||||
},
|
||||
@@ -10586,6 +10602,7 @@
|
||||
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"is-docker": "^2.0.0"
|
||||
},
|
||||
@@ -10621,6 +10638,7 @@
|
||||
"resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz",
|
||||
"integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
@@ -10632,6 +10650,7 @@
|
||||
"integrity": "sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
@@ -10781,6 +10800,7 @@
|
||||
"integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.6",
|
||||
"array.prototype.flat": "^1.3.1",
|
||||
@@ -10815,7 +10835,8 @@
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
|
||||
"integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
"license": "CC0-1.0",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/language-tags": {
|
||||
"version": "1.0.9",
|
||||
@@ -10823,6 +10844,7 @@
|
||||
"integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"language-subtag-registry": "^0.3.20"
|
||||
},
|
||||
@@ -10855,6 +10877,7 @@
|
||||
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.102.tgz",
|
||||
"integrity": "sha512-g70kydI0I1sZU0ChO8mBbhw0oUW/8U0GHzygpvEIx8k+jgOpqnTSb/E+70toYVqHxBhrERD21TwD5QcZJQ40ZQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"isomorphic.js": "^0.2.4"
|
||||
},
|
||||
@@ -11179,7 +11202,8 @@
|
||||
"resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
|
||||
"integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
@@ -11206,6 +11230,7 @@
|
||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
@@ -11897,6 +11922,7 @@
|
||||
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
@@ -12245,6 +12271,7 @@
|
||||
"integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"define-lazy-prop": "^2.0.0",
|
||||
"is-docker": "^2.1.1",
|
||||
@@ -12514,6 +12541,7 @@
|
||||
"integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 14.16"
|
||||
}
|
||||
@@ -12665,7 +12693,6 @@
|
||||
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -12782,6 +12809,7 @@
|
||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
@@ -12797,6 +12825,7 @@
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -12809,7 +12838,8 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/prismjs": {
|
||||
"version": "1.30.0",
|
||||
@@ -13010,7 +13040,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -13038,7 +13067,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -13130,7 +13158,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -13181,7 +13208,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.56.3.tgz",
|
||||
"integrity": "sha512-IK18V6GVbab4TAo1/cz3kqajxbDPGofdF0w7VHdCo0Nt8PrPlOZcuuDq9YYIV1BtjcX78x0XsldbQRQnQXWXmw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
@@ -13432,6 +13458,7 @@
|
||||
"integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ast-types": "^0.16.1",
|
||||
"esprima": "~4.0.0",
|
||||
@@ -13449,6 +13476,7 @@
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -13465,6 +13493,7 @@
|
||||
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"indent-string": "^4.0.0",
|
||||
"strip-indent": "^3.0.0"
|
||||
@@ -13479,6 +13508,7 @@
|
||||
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"min-indent": "^1.0.0"
|
||||
},
|
||||
@@ -13693,7 +13723,6 @@
|
||||
"integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
@@ -14204,6 +14233,7 @@
|
||||
"integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -14219,6 +14249,7 @@
|
||||
"integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -14246,6 +14277,7 @@
|
||||
"integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5"
|
||||
@@ -14466,8 +14498,7 @@
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
|
||||
"integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.2.1",
|
||||
@@ -14571,6 +14602,7 @@
|
||||
"integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@@ -14581,6 +14613,7 @@
|
||||
"integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
@@ -14865,7 +14898,6 @@
|
||||
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -15251,7 +15283,6 @@
|
||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
@@ -15669,6 +15700,7 @@
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@@ -15713,7 +15745,6 @@
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
|
||||
"integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
@@ -15864,7 +15895,6 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
|
||||
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 179 KiB |
|
After Width: | Height: | Size: 86 KiB |
@@ -67,7 +67,8 @@ export const createNotification = (
|
||||
...toastProps,
|
||||
autoClose: toastProps.autoClose || 15000,
|
||||
theme: "dark",
|
||||
type: myProps?.type || "info"
|
||||
type: myProps?.type || "info",
|
||||
className: `pointer-events-auto ${toastProps.className}`
|
||||
});
|
||||
|
||||
export const NotificationContainer = () => (
|
||||
|
||||
@@ -9,7 +9,7 @@ import { cva, type VariantProps } from "cva";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
const alertVariants = cva(
|
||||
"w-full bg-mineshaft-800 rounded-lg border border-bunker-400 px-4 py-3 text-sm flex items-center gap-x-4",
|
||||
"w-full bg-mineshaft-800 rounded-lg border border-bunker-400 px-4 py-3 text-sm flex items-center gap-x-3",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
@@ -28,6 +28,7 @@ type AlertProps = {
|
||||
title?: string;
|
||||
hideTitle?: boolean;
|
||||
icon?: React.ReactNode;
|
||||
iconClassName?: string;
|
||||
};
|
||||
|
||||
const variantTitleMap = {
|
||||
@@ -45,36 +46,41 @@ const variantIconMap = {
|
||||
const Alert = forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants> & AlertProps
|
||||
>(({ className, variant, title, icon, hideTitle = false, children, ...props }, ref) => {
|
||||
const defaultTitle = title ?? variantTitleMap[variant ?? "default"];
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
role="alert"
|
||||
className={twMerge(alertVariants({ variant }), className)}
|
||||
{...props}
|
||||
>
|
||||
<div>
|
||||
{typeof icon !== "undefined" ? (
|
||||
<>{icon} </>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
className="text-lg text-primary"
|
||||
icon={variantIconMap[variant ?? "default"]}
|
||||
/>
|
||||
)}
|
||||
>(
|
||||
(
|
||||
{ className, variant, title, icon, hideTitle = false, children, iconClassName, ...props },
|
||||
ref
|
||||
) => {
|
||||
const defaultTitle = title ?? variantTitleMap[variant ?? "default"];
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
role="alert"
|
||||
className={twMerge(alertVariants({ variant }), className)}
|
||||
{...props}
|
||||
>
|
||||
<div>
|
||||
{typeof icon !== "undefined" ? (
|
||||
<>{icon} </>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
className={twMerge("text-lg text-primary", iconClassName)}
|
||||
icon={variantIconMap[variant ?? "default"]}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-1">
|
||||
{hideTitle ? null : (
|
||||
<h5 className="leading-6 font-medium tracking-tight" {...props}>
|
||||
{defaultTitle}
|
||||
</h5>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-1">
|
||||
{hideTitle ? null : (
|
||||
<h5 className="leading-6 font-medium tracking-tight" {...props}>
|
||||
{defaultTitle}
|
||||
</h5>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
Alert.displayName = "Alert";
|
||||
|
||||
const AlertDescription = forwardRef<
|
||||
|
||||
@@ -55,6 +55,19 @@ export const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
|
||||
{...props}
|
||||
ref={forwardedRef}
|
||||
className={twMerge(drawerContentVariation({ direction, className }))}
|
||||
onPointerDownOutside={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const toastElement = target.closest('[class*="Toastify"]');
|
||||
if (toastElement) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (onClose) {
|
||||
onClose();
|
||||
}
|
||||
props.onPointerDownOutside?.(e);
|
||||
}}
|
||||
>
|
||||
<Card isRounded={false} className="dark h-full w-full">
|
||||
{title && (
|
||||
|
||||
@@ -15,6 +15,7 @@ export type ModalContentProps = Omit<DialogPrimitive.DialogContentProps, "title"
|
||||
onClose?: () => void;
|
||||
overlayClassName?: string;
|
||||
showCloseButton?: boolean;
|
||||
closeOnOutsideClick?: boolean;
|
||||
};
|
||||
|
||||
export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
||||
@@ -29,6 +30,7 @@ export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
||||
bodyClassName,
|
||||
onClose,
|
||||
showCloseButton = true,
|
||||
closeOnOutsideClick = true,
|
||||
...props
|
||||
},
|
||||
forwardedRef
|
||||
@@ -38,7 +40,23 @@ export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
||||
className={twMerge("animate-fade-in fixed inset-0 z-30 h-full w-full", overlayClassName)}
|
||||
style={{ backgroundColor: "rgba(0, 0, 0, 0.7)" }}
|
||||
/>
|
||||
<DialogPrimitive.Content {...props} ref={forwardedRef}>
|
||||
<DialogPrimitive.Content
|
||||
{...props}
|
||||
ref={forwardedRef}
|
||||
onPointerDownOutside={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const toastElement = target.closest('[class*="Toastify"]');
|
||||
if (toastElement) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (closeOnOutsideClick && onClose) {
|
||||
onClose();
|
||||
}
|
||||
props.onPointerDownOutside?.(e);
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
isRounded
|
||||
className={twMerge(
|
||||
|
||||
@@ -26,9 +26,6 @@ export const envConfig = {
|
||||
import.meta.env.VITE_TELEMETRY_CAPTURING_ENABLED === true
|
||||
);
|
||||
},
|
||||
get ACME_FEATURE_ENABLED() {
|
||||
return window?.__INFISICAL_RUNTIME_ENV__?.ACME_FEATURE_ENABLED ?? false;
|
||||
},
|
||||
|
||||
get PLATFORM_VERSION() {
|
||||
return import.meta.env.VITE_INFISICAL_PLATFORM_VERSION;
|
||||
|
||||
@@ -78,7 +78,11 @@ export enum ProjectPermissionIdentityActions {
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
GrantPrivileges = "grant-privileges",
|
||||
AssumePrivileges = "assume-privileges"
|
||||
AssumePrivileges = "assume-privileges",
|
||||
RevokeAuth = "revoke-auth",
|
||||
CreateToken = "create-token",
|
||||
GetToken = "get-token",
|
||||
DeleteToken = "delete-token"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionMemberActions {
|
||||
|
||||
@@ -7,7 +7,6 @@ declare global {
|
||||
POSTHOG_API_KEY?: string;
|
||||
INTERCOM_ID?: string;
|
||||
TELEMETRY_CAPTURING_ENABLED: string;
|
||||
ACME_FEATURE_ENABLED?: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +251,17 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[EventType.UPDATE_ORG_ROLE]: "Update Org Role",
|
||||
[EventType.DELETE_ORG_ROLE]: "Delete Org Role",
|
||||
|
||||
[EventType.CREATE_SUB_ORGANIZATION]: "Create Sub Organization",
|
||||
[EventType.UPDATE_SUB_ORGANIZATION]: "Update Sub Organization",
|
||||
|
||||
[EventType.CREATE_IDENTITY_ORG_MEMBERSHIP]: "Create Identity Org Membership",
|
||||
[EventType.UPDATE_IDENTITY_ORG_MEMBERSHIP]: "Update Identity Org Membership",
|
||||
[EventType.DELETE_IDENTITY_ORG_MEMBERSHIP]: "Delete Identity Org Membership",
|
||||
|
||||
[EventType.CREATE_IDENTITY_PROJECT_MEMBERSHIP]: "Create Identity Project Membership",
|
||||
[EventType.UPDATE_IDENTITY_PROJECT_MEMBERSHIP]: "Update Identity Project Membership",
|
||||
[EventType.DELETE_IDENTITY_PROJECT_MEMBERSHIP]: "Delete Identity Project Membership",
|
||||
|
||||
[EventType.PAM_SESSION_START]: "PAM Session Start",
|
||||
[EventType.PAM_SESSION_LOGS_UPDATE]: "PAM Session Logs Update",
|
||||
[EventType.PAM_SESSION_END]: "PAM Session End",
|
||||
|
||||
@@ -243,6 +243,17 @@ export enum EventType {
|
||||
UPDATE_ORG_ROLE = "update-org-role",
|
||||
DELETE_ORG_ROLE = "delete-org-role",
|
||||
|
||||
CREATE_SUB_ORGANIZATION = "create-sub-organization",
|
||||
UPDATE_SUB_ORGANIZATION = "update-sub-organization",
|
||||
|
||||
CREATE_IDENTITY_ORG_MEMBERSHIP = "create-identity-org-membership",
|
||||
UPDATE_IDENTITY_ORG_MEMBERSHIP = "update-identity-org-membership",
|
||||
DELETE_IDENTITY_ORG_MEMBERSHIP = "delete-identity-org-membership",
|
||||
|
||||
CREATE_IDENTITY_PROJECT_MEMBERSHIP = "create-identity-project-membership",
|
||||
UPDATE_IDENTITY_PROJECT_MEMBERSHIP = "update-identity-project-membership",
|
||||
DELETE_IDENTITY_PROJECT_MEMBERSHIP = "delete-identity-project-membership",
|
||||
|
||||
PAM_SESSION_START = "pam-session-start",
|
||||
PAM_SESSION_LOGS_UPDATE = "pam-session-logs-update",
|
||||
PAM_SESSION_END = "pam-session-end",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { projectIdentityQuery, projectKeys } from "@app/hooks/api";
|
||||
|
||||
import { organizationKeys } from "../organization/queries";
|
||||
import { subscriptionQueryKeys } from "../subscriptions/queries";
|
||||
import { identitiesKeys } from "./queries";
|
||||
import {
|
||||
AddIdentityAliCloudAuthDTO,
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
ClearIdentityLdapAuthLockoutsDTO,
|
||||
ClearIdentityUniversalAuthLockoutsDTO,
|
||||
ClientSecretData,
|
||||
CreateIdentityDTO,
|
||||
CreateIdentityUniversalAuthClientSecretDTO,
|
||||
CreateIdentityUniversalAuthClientSecretRes,
|
||||
CreateTokenIdentityTokenAuthDTO,
|
||||
@@ -29,7 +28,6 @@ import {
|
||||
DeleteIdentityAliCloudAuthDTO,
|
||||
DeleteIdentityAwsAuthDTO,
|
||||
DeleteIdentityAzureAuthDTO,
|
||||
DeleteIdentityDTO,
|
||||
DeleteIdentityGcpAuthDTO,
|
||||
DeleteIdentityJwtAuthDTO,
|
||||
DeleteIdentityKubernetesAuthDTO,
|
||||
@@ -40,7 +38,6 @@ import {
|
||||
DeleteIdentityTokenAuthDTO,
|
||||
DeleteIdentityUniversalAuthClientSecretDTO,
|
||||
DeleteIdentityUniversalAuthDTO,
|
||||
Identity,
|
||||
IdentityAccessToken,
|
||||
IdentityAliCloudAuth,
|
||||
IdentityAwsAuth,
|
||||
@@ -59,7 +56,6 @@ import {
|
||||
UpdateIdentityAliCloudAuthDTO,
|
||||
UpdateIdentityAwsAuthDTO,
|
||||
UpdateIdentityAzureAuthDTO,
|
||||
UpdateIdentityDTO,
|
||||
UpdateIdentityGcpAuthDTO,
|
||||
UpdateIdentityJwtAuthDTO,
|
||||
UpdateIdentityKubernetesAuthDTO,
|
||||
@@ -72,73 +68,6 @@ import {
|
||||
UpdateTokenIdentityTokenAuthDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, CreateIdentityDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.post("/api/v1/identities/", body);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, UpdateIdentityDTO>({
|
||||
mutationFn: async ({ identityId, name, role, hasDeleteProtection, metadata }) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.patch(`/api/v1/identities/${identityId}`, {
|
||||
name,
|
||||
role,
|
||||
hasDeleteProtection,
|
||||
metadata
|
||||
});
|
||||
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, DeleteIdentityDTO>({
|
||||
mutationFn: async ({ identityId }) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.delete(`/api/v1/identities/${identityId}`);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: move these to /auth
|
||||
|
||||
export const useAddIdentityUniversalAuth = () => {
|
||||
@@ -171,10 +100,20 @@ export const useAddIdentityUniversalAuth = () => {
|
||||
});
|
||||
return identityUniversalAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
|
||||
@@ -215,10 +154,20 @@ export const useUpdateIdentityUniversalAuth = () => {
|
||||
});
|
||||
return identityUniversalAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
|
||||
@@ -236,10 +185,20 @@ export const useDeleteIdentityUniversalAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/universal-auth/identities/${identityId}`);
|
||||
return identityUniversalAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityUniversalAuth(identityId)
|
||||
@@ -344,10 +303,20 @@ export const useAddIdentityGcpAuth = () => {
|
||||
|
||||
return identityGcpAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityGcpAuth(identityId) });
|
||||
}
|
||||
@@ -386,10 +355,20 @@ export const useUpdateIdentityGcpAuth = () => {
|
||||
|
||||
return identityGcpAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityGcpAuth(identityId) });
|
||||
}
|
||||
@@ -405,10 +384,20 @@ export const useDeleteIdentityGcpAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/gcp-auth/identities/${identityId}`);
|
||||
return identityGcpAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityGcpAuth(identityId) });
|
||||
}
|
||||
@@ -445,10 +434,20 @@ export const useAddIdentityAwsAuth = () => {
|
||||
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAwsAuth(identityId) });
|
||||
}
|
||||
@@ -485,10 +484,20 @@ export const useUpdateIdentityAwsAuth = () => {
|
||||
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAwsAuth(identityId) });
|
||||
}
|
||||
@@ -504,10 +513,20 @@ export const useDeleteIdentityAwsAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/aws-auth/identities/${identityId}`);
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAwsAuth(identityId) });
|
||||
}
|
||||
@@ -542,10 +561,20 @@ export const useAddIdentityOciAuth = () => {
|
||||
|
||||
return identityOciAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOciAuth(identityId) });
|
||||
}
|
||||
@@ -580,10 +609,20 @@ export const useUpdateIdentityOciAuth = () => {
|
||||
|
||||
return identityOciAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOciAuth(identityId) });
|
||||
}
|
||||
@@ -599,10 +638,20 @@ export const useDeleteIdentityOciAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/oci-auth/identities/${identityId}`);
|
||||
return identityOciAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOciAuth(identityId) });
|
||||
}
|
||||
@@ -635,10 +684,20 @@ export const useAddIdentityAliCloudAuth = () => {
|
||||
|
||||
return identityAliCloudAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityAliCloudAuth(identityId)
|
||||
@@ -673,10 +732,20 @@ export const useUpdateIdentityAliCloudAuth = () => {
|
||||
|
||||
return identityAliCloudAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityAliCloudAuth(identityId)
|
||||
@@ -694,10 +763,20 @@ export const useDeleteIdentityAliCloudAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/alicloud-auth/identities/${identityId}`);
|
||||
return identityAliCloudAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityAliCloudAuth(identityId)
|
||||
@@ -734,10 +813,20 @@ export const useAddIdentityTlsCertAuth = () => {
|
||||
|
||||
return identityTlsCertAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTlsCertAuth(identityId)
|
||||
@@ -774,10 +863,20 @@ export const useUpdateIdentityTlsCertAuth = () => {
|
||||
|
||||
return identityTlsCertAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTlsCertAuth(identityId)
|
||||
@@ -795,10 +894,20 @@ export const useDeleteIdentityTlsCertAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/tls-cert-auth/identities/${identityId}`);
|
||||
return identityTlsCertAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTlsCertAuth(identityId)
|
||||
@@ -845,10 +954,20 @@ export const useUpdateIdentityOidcAuth = () => {
|
||||
|
||||
return identityOidcAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOidcAuth(identityId) });
|
||||
}
|
||||
@@ -893,10 +1012,20 @@ export const useAddIdentityOidcAuth = () => {
|
||||
|
||||
return identityOidcAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOidcAuth(identityId) });
|
||||
}
|
||||
@@ -912,10 +1041,20 @@ export const useDeleteIdentityOidcAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/oidc-auth/identities/${identityId}`);
|
||||
return identityOidcAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityOidcAuth(identityId) });
|
||||
}
|
||||
@@ -961,10 +1100,20 @@ export const useUpdateIdentityJwtAuth = () => {
|
||||
|
||||
return identityJwtAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityJwtAuth(identityId) });
|
||||
}
|
||||
@@ -1011,10 +1160,20 @@ export const useAddIdentityJwtAuth = () => {
|
||||
|
||||
return identityJwtAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityJwtAuth(identityId) });
|
||||
}
|
||||
@@ -1030,10 +1189,20 @@ export const useDeleteIdentityJwtAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/jwt-auth/identities/${identityId}`);
|
||||
return identityJwtAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityJwtAuth(identityId) });
|
||||
}
|
||||
@@ -1070,10 +1239,20 @@ export const useAddIdentityAzureAuth = () => {
|
||||
|
||||
return identityAzureAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId)
|
||||
@@ -1122,10 +1301,20 @@ export const useAddIdentityKubernetesAuth = () => {
|
||||
|
||||
return identityKubernetesAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAzureAuth(identityId) });
|
||||
}
|
||||
@@ -1162,10 +1351,20 @@ export const useUpdateIdentityAzureAuth = () => {
|
||||
|
||||
return identityAzureAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAzureAuth(identityId) });
|
||||
}
|
||||
@@ -1181,10 +1380,20 @@ export const useDeleteIdentityAzureAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/azure-auth/identities/${identityId}`);
|
||||
return identityAzureAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityAzureAuth(identityId) });
|
||||
}
|
||||
@@ -1231,10 +1440,20 @@ export const useUpdateIdentityKubernetesAuth = () => {
|
||||
|
||||
return identityKubernetesAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId)
|
||||
@@ -1252,10 +1471,20 @@ export const useDeleteIdentityKubernetesAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/kubernetes-auth/identities/${identityId}`);
|
||||
return identityKubernetesAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityKubernetesAuth(identityId)
|
||||
@@ -1288,10 +1517,20 @@ export const useAddIdentityTokenAuth = () => {
|
||||
|
||||
return identityTokenAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTokenAuth(identityId)
|
||||
@@ -1324,10 +1563,20 @@ export const useUpdateIdentityTokenAuth = () => {
|
||||
|
||||
return identityTokenAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityTokenAuth(identityId)
|
||||
@@ -1345,10 +1594,20 @@ export const useDeleteIdentityTokenAuth = () => {
|
||||
} = await apiRequest.delete(`/api/v1/auth/token-auth/identities/${identityId}`);
|
||||
return identityTokenAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityTokenAuth(identityId) });
|
||||
}
|
||||
@@ -1462,10 +1721,20 @@ export const useAddIdentityLdapAuth = () => {
|
||||
);
|
||||
return data.identityLdapAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityLdapAuth(identityId)
|
||||
@@ -1519,10 +1788,20 @@ export const useUpdateIdentityLdapAuth = () => {
|
||||
);
|
||||
return data.identityLdapAuth;
|
||||
},
|
||||
onSuccess: (_, { identityId, organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { identityId, organizationId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityLdapAuth(identityId)
|
||||
@@ -1538,10 +1817,20 @@ export const useDeleteIdentityLdapAuth = () => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/auth/ldap-auth/identities/${identityId}`);
|
||||
return data.identityLdapAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
onSuccess: (_, { organizationId, identityId, projectId }) => {
|
||||
if (organizationId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
}
|
||||
if (projectId) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectIdentityQuery.getByIdKey({ identityId, projectId })
|
||||
});
|
||||
}
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityLdapAuth(identityId)
|
||||
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
IdentityJwtAuth,
|
||||
IdentityKubernetesAuth,
|
||||
IdentityLdapAuth,
|
||||
IdentityMembership,
|
||||
IdentityMembershipOrg,
|
||||
IdentityOciAuth,
|
||||
IdentityOidcAuth,
|
||||
IdentityProjectMembershipV1,
|
||||
IdentityTlsCertAuth,
|
||||
IdentityTokenAuth,
|
||||
IdentityUniversalAuth,
|
||||
@@ -52,7 +52,7 @@ export const identitiesKeys = {
|
||||
[{ identityId }, "identity-project-memberships"] as const
|
||||
};
|
||||
|
||||
export const useGetIdentityById = (identityId: string) => {
|
||||
export const useGetOrgIdentityMembershipById = (identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(identityId),
|
||||
queryKey: identitiesKeys.getIdentityById(identityId),
|
||||
@@ -67,7 +67,7 @@ export const useGetIdentityById = (identityId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useSearchIdentities = (dto: TSearchIdentitiesDTO) => {
|
||||
export const useSearchOrgIdentityMemberships = (dto: TSearchIdentitiesDTO) => {
|
||||
const { limit, search, offset, orderBy, orderDirection } = dto;
|
||||
return useQuery({
|
||||
queryKey: identitiesKeys.searchIdentities(dto),
|
||||
@@ -95,7 +95,7 @@ export const useGetIdentityProjectMemberships = (identityId: string) => {
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMemberships }
|
||||
} = await apiRequest.get<{ identityMemberships: IdentityMembership[] }>(
|
||||
} = await apiRequest.get<{ identityMemberships: IdentityProjectMembershipV1[] }>(
|
||||
`/api/v1/identities/${identityId}/identity-memberships`
|
||||
);
|
||||
return identityMemberships;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { TemporaryPermissionMode } from "@app/hooks/api/shared";
|
||||
|
||||
import { OrderByDirection } from "../generic/types";
|
||||
import { OrgIdentityOrderBy } from "../organization/types";
|
||||
import { Project, ProjectUserMembershipTemporaryMode } from "../projects/types";
|
||||
import { Project } from "../projects/types";
|
||||
import { TOrgRole } from "../roles/types";
|
||||
import { IdentityAuthMethod, IdentityJwtConfigurationType } from "./enums";
|
||||
|
||||
@@ -21,6 +23,8 @@ export type Identity = {
|
||||
updatedAt: string;
|
||||
isInstanceAdmin?: boolean;
|
||||
orgId: string;
|
||||
projectId?: string | null;
|
||||
metadata?: { key: string; value: string; id: string }[];
|
||||
};
|
||||
|
||||
export type IdentityAccessToken = {
|
||||
@@ -52,7 +56,7 @@ export type IdentityMembershipOrg = {
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type IdentityMembership = {
|
||||
export type IdentityProjectMembershipV1 = {
|
||||
id: string;
|
||||
identity: Identity;
|
||||
project: Pick<Project, "id" | "name" | "type">;
|
||||
@@ -74,7 +78,7 @@ export type IdentityMembership = {
|
||||
| {
|
||||
isTemporary: true;
|
||||
temporaryRange: string;
|
||||
temporaryMode: ProjectUserMembershipTemporaryMode;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryAccessEndTime: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
@@ -82,6 +86,41 @@ export type IdentityMembership = {
|
||||
>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
lastLoginTime?: string;
|
||||
lastLoginAuthMethod?: IdentityAuthMethod;
|
||||
};
|
||||
|
||||
export type IdentityProjectMembershipV2 = {
|
||||
id: string;
|
||||
identity: Identity;
|
||||
roles: Array<
|
||||
{
|
||||
id: string;
|
||||
role: "owner" | "admin" | "member" | "no-access" | "custom";
|
||||
customRoleId: string;
|
||||
customRoleName: string;
|
||||
customRoleSlug: string;
|
||||
} & (
|
||||
| {
|
||||
isTemporary: false;
|
||||
temporaryRange: null;
|
||||
temporaryMode: null;
|
||||
temporaryAccessEndTime: null;
|
||||
temporaryAccessStartTime: null;
|
||||
}
|
||||
| {
|
||||
isTemporary: true;
|
||||
temporaryRange: string;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryAccessEndTime: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
)
|
||||
>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
lastLoginTime?: string;
|
||||
lastLoginAuthMethod?: IdentityAuthMethod;
|
||||
};
|
||||
|
||||
export type CreateIdentityDTO = {
|
||||
@@ -122,7 +161,8 @@ export type IdentityUniversalAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityUniversalAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
clientSecretTrustedIps: {
|
||||
ipAddress: string;
|
||||
@@ -138,10 +178,11 @@ export type AddIdentityUniversalAuthDTO = {
|
||||
lockoutThreshold: number;
|
||||
lockoutDurationSeconds: number;
|
||||
lockoutCounterResetSeconds: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityUniversalAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
clientSecretTrustedIps?: {
|
||||
ipAddress: string;
|
||||
@@ -157,12 +198,13 @@ export type UpdateIdentityUniversalAuthDTO = {
|
||||
lockoutThreshold?: number;
|
||||
lockoutDurationSeconds?: number;
|
||||
lockoutCounterResetSeconds?: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityUniversalAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityGcpAuth = {
|
||||
identityId: string;
|
||||
@@ -177,7 +219,8 @@ export type IdentityGcpAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityGcpAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
type: "iam" | "gce";
|
||||
allowedServiceAccounts: string;
|
||||
@@ -189,10 +232,11 @@ export type AddIdentityGcpAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityGcpAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
type?: "iam" | "gce";
|
||||
allowedServiceAccounts?: string;
|
||||
@@ -204,12 +248,13 @@ export type UpdateIdentityGcpAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityGcpAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityOidcAuth = {
|
||||
identityId: string;
|
||||
@@ -227,7 +272,8 @@ export type IdentityOidcAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityOidcAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
oidcDiscoveryUrl: string;
|
||||
caCert: string;
|
||||
@@ -242,10 +288,11 @@ export type AddIdentityOidcAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityOidcAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
oidcDiscoveryUrl?: string;
|
||||
caCert?: string;
|
||||
@@ -260,12 +307,13 @@ export type UpdateIdentityOidcAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityOidcAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityAwsAuth = {
|
||||
identityId: string;
|
||||
@@ -280,7 +328,8 @@ export type IdentityAwsAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
stsEndpoint: string;
|
||||
allowedPrincipalArns: string;
|
||||
@@ -291,10 +340,11 @@ export type AddIdentityAwsAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
stsEndpoint?: string;
|
||||
allowedPrincipalArns?: string;
|
||||
@@ -308,9 +358,10 @@ export type UpdateIdentityAwsAuthDTO = {
|
||||
};
|
||||
|
||||
export type DeleteIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityAliCloudAuth = {
|
||||
identityId: string;
|
||||
@@ -323,7 +374,8 @@ export type IdentityAliCloudAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityAliCloudAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
allowedArns: string;
|
||||
accessTokenTTL: number;
|
||||
@@ -332,10 +384,11 @@ export type AddIdentityAliCloudAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityAliCloudAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
allowedArns: string;
|
||||
accessTokenTTL?: number;
|
||||
@@ -344,12 +397,13 @@ export type UpdateIdentityAliCloudAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityAliCloudAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityOciAuth = {
|
||||
identityId: string;
|
||||
@@ -363,7 +417,8 @@ export type IdentityOciAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityOciAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenancyOcid: string;
|
||||
allowedUsernames?: string | null;
|
||||
@@ -373,10 +428,11 @@ export type AddIdentityOciAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityOciAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenancyOcid?: string;
|
||||
allowedUsernames?: string | null;
|
||||
@@ -386,12 +442,13 @@ export type UpdateIdentityOciAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityOciAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityAzureAuth = {
|
||||
identityId: string;
|
||||
@@ -405,7 +462,8 @@ export type IdentityAzureAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityAzureAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenantId: string;
|
||||
resource: string;
|
||||
@@ -416,10 +474,11 @@ export type AddIdentityAzureAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityAzureAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
tenantId?: string;
|
||||
resource?: string;
|
||||
@@ -430,12 +489,13 @@ export type UpdateIdentityAzureAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityAzureAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export enum IdentityKubernetesAuthTokenReviewMode {
|
||||
Api = "api",
|
||||
@@ -459,7 +519,8 @@ export type IdentityKubernetesAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityKubernetesAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
kubernetesHost: string | null;
|
||||
tokenReviewerJwt?: string;
|
||||
@@ -475,10 +536,11 @@ export type AddIdentityKubernetesAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityKubernetesAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
kubernetesHost?: string | null;
|
||||
tokenReviewerJwt?: string | null;
|
||||
@@ -494,12 +556,13 @@ export type UpdateIdentityKubernetesAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityKubernetesAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityTlsCertAuth = {
|
||||
identityId: string;
|
||||
@@ -512,7 +575,8 @@ export type IdentityTlsCertAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityTlsCertAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
caCertificate: string;
|
||||
allowedCommonNames?: string;
|
||||
@@ -522,10 +586,11 @@ export type AddIdentityTlsCertAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityTlsCertAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
caCertificate: string;
|
||||
allowedCommonNames?: string | null;
|
||||
@@ -535,12 +600,13 @@ export type UpdateIdentityTlsCertAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityTlsCertAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type CreateIdentityUniversalAuthClientSecretDTO = {
|
||||
identityId: string;
|
||||
@@ -585,7 +651,8 @@ export type IdentityTokenAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityLdapAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
templateId?: string;
|
||||
url?: string;
|
||||
@@ -609,11 +676,12 @@ export type AddIdentityLdapAuthDTO = {
|
||||
lockoutThreshold: number;
|
||||
lockoutDurationSeconds: number;
|
||||
lockoutCounterResetSeconds: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityLdapAuthDTO = {
|
||||
identityId: string;
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
templateId?: string;
|
||||
url?: string;
|
||||
bindDN?: string;
|
||||
@@ -636,12 +704,13 @@ export type UpdateIdentityLdapAuthDTO = {
|
||||
lockoutThreshold?: number;
|
||||
lockoutDurationSeconds?: number;
|
||||
lockoutCounterResetSeconds?: number;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityLdapAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityLdapAuth = {
|
||||
url?: string;
|
||||
@@ -673,7 +742,8 @@ export type ClearIdentityLdapAuthLockoutsDTO = {
|
||||
};
|
||||
|
||||
export type AddIdentityTokenAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
accessTokenTTL: number;
|
||||
accessTokenMaxTTL: number;
|
||||
@@ -681,10 +751,11 @@ export type AddIdentityTokenAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityTokenAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
accessTokenTTL?: number;
|
||||
accessTokenMaxTTL?: number;
|
||||
@@ -692,12 +763,13 @@ export type UpdateIdentityTokenAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityTokenAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type IdentityJwtAuth = {
|
||||
identityId: string;
|
||||
@@ -716,7 +788,8 @@ export type IdentityJwtAuth = {
|
||||
};
|
||||
|
||||
export type AddIdentityJwtAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
configurationType: string;
|
||||
jwksUrl?: string;
|
||||
@@ -732,10 +805,11 @@ export type AddIdentityJwtAuthDTO = {
|
||||
accessTokenTrustedIps: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type UpdateIdentityJwtAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
configurationType?: string;
|
||||
jwksUrl?: string;
|
||||
@@ -751,12 +825,13 @@ export type UpdateIdentityJwtAuthDTO = {
|
||||
accessTokenTrustedIps?: {
|
||||
ipAddress: string;
|
||||
}[];
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type DeleteIdentityJwtAuthDTO = {
|
||||
organizationId: string;
|
||||
organizationId?: string;
|
||||
projectId?: string;
|
||||
identityId: string;
|
||||
};
|
||||
} & ({ organizationId: string } | { projectId: string });
|
||||
|
||||
export type CreateTokenIdentityTokenAuthDTO = {
|
||||
identityId: string;
|
||||
@@ -785,8 +860,13 @@ export type RevokeTokenRes = {
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type TProjectIdentitiesList = {
|
||||
identityMemberships: IdentityMembership[];
|
||||
export type TProjectIdentityMembershipsList = {
|
||||
identityMemberships: IdentityProjectMembershipV1[];
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
export type TProjectIdentityMembershipsListV2 = {
|
||||
identityMemberships: IdentityProjectMembershipV2[];
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
|
||||
@@ -25,10 +25,14 @@ export * from "./ldapConfig";
|
||||
export * from "./oidcConfig";
|
||||
export * from "./orgAdmin";
|
||||
export * from "./organization";
|
||||
export * from "./orgIdentity";
|
||||
export * from "./orgIdentityMembership";
|
||||
export * from "./pkiAlerts";
|
||||
export * from "./pkiCollections";
|
||||
export * from "./pkiSubscriber";
|
||||
export * from "./pkiSyncs";
|
||||
export * from "./projectIdentity";
|
||||
export * from "./projectIdentityMembership";
|
||||
export * from "./projects";
|
||||
export * from "./projectUserAdditionalPrivilege";
|
||||
export * from "./rateLimit";
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./mutations";
|
||||
export * from "./queries";
|
||||
export type * from "./types";
|
||||
@@ -0,0 +1,116 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { identitiesKeys } from "@app/hooks/api";
|
||||
import { CreateIdentityDTO, Identity, UpdateIdentityDTO } from "@app/hooks/api/identities/types";
|
||||
import { organizationKeys } from "@app/hooks/api/organization/queries";
|
||||
import { subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
|
||||
|
||||
import { orgIdentityQuery } from "./queries";
|
||||
import { TDeleteOrgIdentityDTO, TOrgIdentity } from "./types";
|
||||
|
||||
// TODO (scott/akhi): eventually move to the new api commented out below; the current ones use old api
|
||||
|
||||
export const useCreateOrgIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, CreateIdentityDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.post("/api/v1/identities/", body);
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateOrgIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<Identity, object, UpdateIdentityDTO>({
|
||||
mutationFn: async ({ identityId, name, role, hasDeleteProtection, metadata }) => {
|
||||
const {
|
||||
data: { identity }
|
||||
} = await apiRequest.patch(`/api/v1/identities/${identityId}`, {
|
||||
name,
|
||||
role,
|
||||
hasDeleteProtection,
|
||||
metadata
|
||||
});
|
||||
|
||||
return identity;
|
||||
},
|
||||
onSuccess: (_, { organizationId, identityId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(organizationId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(identityId) });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// export const useCreateOrgIdentity = () => {
|
||||
// const queryClient = useQueryClient();
|
||||
// return useMutation({
|
||||
// mutationFn: async (dto: TCreateOrgIdentityDTO) => {
|
||||
// const { data } = await apiRequest.post<{ identity: TOrgIdentity }>(
|
||||
// "/api/v1/organization/identities",
|
||||
// dto
|
||||
// );
|
||||
// return data;
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// queryClient.invalidateQueries({ queryKey: orgIdentityQuery.allKey() });
|
||||
// queryClient.invalidateQueries({
|
||||
// queryKey: subscriptionQueryKeys.all()
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
//
|
||||
// export const useUpdateOrgIdentity = () => {
|
||||
// const queryClient = useQueryClient();
|
||||
// return useMutation({
|
||||
// mutationFn: async ({ identityId, ...updates }: TUpdateOrgIdentityDTO) => {
|
||||
// const { data } = await apiRequest.patch<{ identity: TOrgIdentity }>(
|
||||
// `/api/v1/organization/identities/${identityId}`,
|
||||
// updates
|
||||
// );
|
||||
// return data;
|
||||
// },
|
||||
// onSuccess: () => {
|
||||
// queryClient.invalidateQueries({ queryKey: orgIdentityQuery.allKey() });
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
export const useDeleteOrgIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId }: TDeleteOrgIdentityDTO) => {
|
||||
const { data } = await apiRequest.delete<{ identity: TOrgIdentity }>(
|
||||
`/api/v1/identities/${identityId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { orgId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: organizationKeys.getOrgIdentityMemberships(orgId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.searchIdentitiesRoot });
|
||||
queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityById(orgId) });
|
||||
queryClient.invalidateQueries({ queryKey: orgIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.all()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TGetOrgIdentityByIdDTO, TListOrgIdentitiesDTO, TOrgIdentity } from "./types";
|
||||
|
||||
export const orgIdentityQuery = {
|
||||
allKey: () => ["organization-identities"] as const,
|
||||
getByIdKey: (params: TGetOrgIdentityByIdDTO) =>
|
||||
[...orgIdentityQuery.allKey(), "by-id", params] as const,
|
||||
listKey: (params?: TListOrgIdentitiesDTO) =>
|
||||
[...orgIdentityQuery.allKey(), "list", params] as const,
|
||||
getById: (params: TGetOrgIdentityByIdDTO) =>
|
||||
queryOptions({
|
||||
queryKey: orgIdentityQuery.getByIdKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ identity: TOrgIdentity }>(
|
||||
`/api/v1/organization/identities/${params.identityId}`
|
||||
);
|
||||
return data.identity;
|
||||
}
|
||||
}),
|
||||
list: (params: TListOrgIdentitiesDTO = {}) =>
|
||||
queryOptions({
|
||||
queryKey: orgIdentityQuery.listKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TOrgIdentity[];
|
||||
totalCount: number;
|
||||
}>("/api/v1/organization/identities", {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
search: params.search
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { TIdentity, TMetadata } from "@app/hooks/api/shared";
|
||||
|
||||
export type TOrgIdentity = TIdentity;
|
||||
|
||||
export type TCreateOrgIdentityDTO = {
|
||||
name: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata;
|
||||
};
|
||||
|
||||
export type TUpdateOrgIdentityDTO = {
|
||||
identityId: string;
|
||||
name?: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata;
|
||||
};
|
||||
|
||||
export type TGetOrgIdentityByIdDTO = {
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export type TListOrgIdentitiesDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
};
|
||||
|
||||
export type TDeleteOrgIdentityDTO = {
|
||||
identityId: string;
|
||||
orgId: string;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import {
|
||||
TAvailableOrganizationIdentities,
|
||||
TListAvailableOrganizationIdentitiesDTO,
|
||||
TListOrgIdentityMembershipsDTO
|
||||
} from "./types";
|
||||
|
||||
export const orgIdentityMembershipQuery = {
|
||||
allKey: () => ["organization-identity-memberships"] as const,
|
||||
listAvailableKey: (params?: TListOrgIdentityMembershipsDTO) =>
|
||||
[...orgIdentityMembershipQuery.allKey(), "list-available", params] as const,
|
||||
listAvailable: (params: TListAvailableOrganizationIdentitiesDTO = {}) =>
|
||||
queryOptions({
|
||||
queryKey: orgIdentityMembershipQuery.listAvailableKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TAvailableOrganizationIdentities;
|
||||
}>("/api/v1/organization/available-identities", {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
identityName: params.identityName
|
||||
}
|
||||
});
|
||||
return data.identities;
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -1,6 +1,4 @@
|
||||
export enum TemporaryPermissionMode {
|
||||
Relative = "relative"
|
||||
}
|
||||
import { TRoles } from "@app/hooks/api/shared";
|
||||
|
||||
export type TOrgIdentityMembership = {
|
||||
id: string;
|
||||
@@ -12,21 +10,24 @@ export type TOrgIdentityMembership = {
|
||||
|
||||
export type TCreateOrgIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
roles: Array<
|
||||
| {
|
||||
role: string;
|
||||
isTemporary?: false;
|
||||
}
|
||||
| {
|
||||
role: string;
|
||||
isTemporary: true;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryRange: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
>;
|
||||
roles: TRoles;
|
||||
};
|
||||
|
||||
export type TDeleteOrgIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export type TListOrgIdentityMembershipsDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
identityName?: string;
|
||||
roles?: string[];
|
||||
};
|
||||
|
||||
export type TListAvailableOrganizationIdentitiesDTO = {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
identityName?: string;
|
||||
};
|
||||
|
||||
export type TAvailableOrganizationIdentities = Array<{ id: string; name: string }>;
|
||||
|
||||
@@ -6,7 +6,6 @@ export {
|
||||
useDeleteOrgById,
|
||||
useDeleteOrgPmtMethod,
|
||||
useDeleteOrgTaxId,
|
||||
useGetAvailableOrgIdentities,
|
||||
useGetIdentityMembershipOrgs,
|
||||
useGetOrganizationGroups,
|
||||
useGetOrganizations,
|
||||
|
||||
@@ -579,19 +579,6 @@ export const useGetOrgIntegrationAuths = <TData = IntegrationAuth[],>(
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetAvailableOrgIdentities = (enabled = true) =>
|
||||
useQuery({
|
||||
queryKey: organizationKeys.getAvailableIdentities(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ identities: { name: string; id: string }[] }>(
|
||||
"/api/v1/organization/identities/available"
|
||||
);
|
||||
|
||||
return data.identities;
|
||||
},
|
||||
enabled
|
||||
});
|
||||
|
||||
export const useGetAvailableOrgUsers = (enabled = true) =>
|
||||
useQuery({
|
||||
queryKey: organizationKeys.getAvailableUsers(),
|
||||
|
||||
@@ -4,7 +4,18 @@ export enum PamResourceType {
|
||||
RDP = "rdp",
|
||||
SSH = "ssh",
|
||||
Kubernetes = "kubernetes",
|
||||
MCP = "mcp"
|
||||
OracleDB = "oracledb",
|
||||
SQLite = "sqlite",
|
||||
MsSQL = "mssql",
|
||||
MCP = "mcp",
|
||||
Redis = "redis",
|
||||
MongoDB = "mongodb",
|
||||
WebApp = "webapp",
|
||||
Cassandra = "cassandra",
|
||||
CockroachDB = "cockroachdb",
|
||||
Elasticsearch = "elasticsearch",
|
||||
Snowflake = "snowflake",
|
||||
DynamoDB = "dynamodb"
|
||||
}
|
||||
|
||||
export enum PamSessionStatus {
|
||||
|
||||
@@ -9,5 +9,16 @@ export const PAM_RESOURCE_TYPE_MAP: Record<
|
||||
[PamResourceType.RDP]: { name: "RDP", image: "RDP.png" },
|
||||
[PamResourceType.SSH]: { name: "SSH", image: "SSH.png" },
|
||||
[PamResourceType.Kubernetes]: { name: "Kubernetes", image: "Kubernetes.png" },
|
||||
[PamResourceType.MCP]: { name: "MCP", image: "MCP.png" }
|
||||
[PamResourceType.OracleDB]: { name: "OracleDB", image: "Oracle.png", size: 55 },
|
||||
[PamResourceType.SQLite]: { name: "SQLite", image: "SQLite.png" },
|
||||
[PamResourceType.MsSQL]: { name: "Microsoft SQL Server", image: "MsSql.png" },
|
||||
[PamResourceType.MCP]: { name: "MCP", image: "MCP.png" },
|
||||
[PamResourceType.Redis]: { name: "Redis", image: "Redis.png" },
|
||||
[PamResourceType.MongoDB]: { name: "MongoDB", image: "MongoDB.png" },
|
||||
[PamResourceType.WebApp]: { name: "Web Application", image: "Web.png" },
|
||||
[PamResourceType.Cassandra]: { name: "Cassandra", image: "Cassandra.png", size: 55 },
|
||||
[PamResourceType.CockroachDB]: { name: "CockroachDB", image: "CockroachDB.png" },
|
||||
[PamResourceType.Elasticsearch]: { name: "Elasticsearch", image: "Elastic.png" },
|
||||
[PamResourceType.Snowflake]: { name: "Snowflake", image: "Snowflake.png" },
|
||||
[PamResourceType.DynamoDB]: { name: "DynamoDB", image: "DynamoDB.png", size: 55 }
|
||||
};
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
export {
|
||||
useCreateProjectIdentity,
|
||||
useDeleteProjectIdentity,
|
||||
useUpdateProjectIdentity
|
||||
} from "./mutations";
|
||||
export { projectIdentityQuery } from "./queries";
|
||||
export type {
|
||||
TCreateProjectIdentityDTO,
|
||||
TDeleteProjectIdentityDTO,
|
||||
TGetProjectIdentityByIdDTO,
|
||||
TListProjectIdentitiesDTO,
|
||||
TProjectIdentity,
|
||||
TProjectIdentityMetadata,
|
||||
TUpdateProjectIdentityDTO
|
||||
} from "./types";
|
||||
@@ -0,0 +1,76 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { identitiesKeys, projectKeys } from "@app/hooks/api";
|
||||
import { subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
|
||||
|
||||
import { projectIdentityQuery } from "./queries";
|
||||
import {
|
||||
TCreateProjectIdentityDTO,
|
||||
TDeleteProjectIdentityDTO,
|
||||
TProjectIdentity,
|
||||
TUpdateProjectIdentityDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateProjectIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ projectId, ...dto }: TCreateProjectIdentityDTO) => {
|
||||
const { data } = await apiRequest.post<{ identity: TProjectIdentity }>(
|
||||
`/api/v1/projects/${projectId}/identities`,
|
||||
dto
|
||||
);
|
||||
return data.identity;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.all()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateProjectIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ projectId, identityId, ...updates }: TUpdateProjectIdentityDTO) => {
|
||||
const { data } = await apiRequest.patch<{ identity: TProjectIdentity }>(
|
||||
`/api/v1/projects/${projectId}/identities/${identityId}`,
|
||||
updates
|
||||
);
|
||||
return data.identity;
|
||||
},
|
||||
onSuccess: (_, { projectId, identityId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteProjectIdentity = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ projectId, identityId }: TDeleteProjectIdentityDTO) => {
|
||||
const { data } = await apiRequest.delete<{ identity: TProjectIdentity }>(
|
||||
`/api/v1/projects/${projectId}/identities/${identityId}`
|
||||
);
|
||||
return data.identity;
|
||||
},
|
||||
onSuccess: (_, { projectId, identityId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: subscriptionQueryKeys.all()
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import { queryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TGetProjectIdentityByIdDTO, TListProjectIdentitiesDTO, TProjectIdentity } from "./types";
|
||||
|
||||
export const projectIdentityQuery = {
|
||||
allKey: () => ["project-identities"] as const,
|
||||
getByIdKey: (params: TGetProjectIdentityByIdDTO) =>
|
||||
[...projectIdentityQuery.allKey(), "by-id", params] as const,
|
||||
listKey: (params: TListProjectIdentitiesDTO) =>
|
||||
[...projectIdentityQuery.allKey(), "list", params] as const,
|
||||
getById: (params: TGetProjectIdentityByIdDTO) =>
|
||||
queryOptions({
|
||||
queryKey: projectIdentityQuery.getByIdKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ identity: TProjectIdentity }>(
|
||||
`/api/v1/projects/${params.projectId}/identities/${params.identityId}`
|
||||
);
|
||||
return data.identity;
|
||||
}
|
||||
}),
|
||||
list: (params: TListProjectIdentitiesDTO) =>
|
||||
queryOptions({
|
||||
queryKey: projectIdentityQuery.listKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TProjectIdentity[];
|
||||
totalCount: number;
|
||||
}>(`/api/v1/projects/${params.projectId}/identities`, {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
search: params.search
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
})
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { TIdentity, TMetadata } from "@app/hooks/api/shared";
|
||||
|
||||
export type TProjectIdentityMetadata = {
|
||||
key: string;
|
||||
value: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export type TProjectIdentity = TIdentity;
|
||||
|
||||
export type TCreateProjectIdentityDTO = {
|
||||
projectId: string;
|
||||
name: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TUpdateProjectIdentityDTO = {
|
||||
projectId: string;
|
||||
identityId: string;
|
||||
name?: string;
|
||||
hasDeleteProtection?: boolean;
|
||||
metadata?: TMetadata[];
|
||||
};
|
||||
|
||||
export type TGetProjectIdentityByIdDTO = {
|
||||
projectId: string;
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export type TListProjectIdentitiesDTO = {
|
||||
projectId: string;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
};
|
||||
|
||||
export type TDeleteProjectIdentityDTO = {
|
||||
projectId: string;
|
||||
identityId: string;
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./mutations";
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,93 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { identitiesKeys, projectKeys } from "@app/hooks/api";
|
||||
import { projectIdentityQuery } from "@app/hooks/api/projectIdentity";
|
||||
|
||||
import {
|
||||
TCreateProjectIdentityMembershipDTO,
|
||||
TDeleteProjectIdentityMembershipDTO,
|
||||
TProjectIdentityMembership,
|
||||
TUpdateProjectIdentityMembershipDTO
|
||||
} from "./types";
|
||||
|
||||
export const useCreateProjectIdentityMembership = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId, role }: TCreateProjectIdentityMembershipDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.post<{ identityMembership: TProjectIdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/memberships/identities/${identityId}`,
|
||||
{
|
||||
role
|
||||
}
|
||||
);
|
||||
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateProjectIdentityMembership = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
projectId,
|
||||
identityId,
|
||||
...updates
|
||||
}: TUpdateProjectIdentityMembershipDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.patch<{ identityMembership: TProjectIdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/memberships/identities/${identityId}`,
|
||||
updates
|
||||
);
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { projectId, identityId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteProjectIdentityMembership = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId }: TDeleteProjectIdentityMembershipDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.delete<{ identityMembership: TProjectIdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/memberships/identities/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectIdentityQuery.allKey() });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
import { queryOptions, useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import {
|
||||
projectKeys,
|
||||
TAvailableProjectIdentities,
|
||||
TListAvailableProjectIdentitiesDTO
|
||||
} from "@app/hooks/api";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import {
|
||||
IdentityProjectMembershipV1,
|
||||
TProjectIdentityMembershipsListV2
|
||||
} from "@app/hooks/api/identities/types";
|
||||
import { ProjectIdentityOrderBy, TListProjectIdentitiesDTO } from "@app/hooks/api/projects/types";
|
||||
|
||||
export const projectIdentityMembershipQuery = {
|
||||
allKey: () => ["project-identity-memberships"] as const,
|
||||
listAvailableKey: (params?: TListAvailableProjectIdentitiesDTO) =>
|
||||
[...projectIdentityMembershipQuery.allKey(), "list-available", params] as const,
|
||||
listAvailable: (params: TListAvailableProjectIdentitiesDTO) =>
|
||||
queryOptions({
|
||||
queryKey: projectIdentityMembershipQuery.listAvailableKey(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
identities: TAvailableProjectIdentities;
|
||||
}>(`/api/v1/projects/${params.projectId}/memberships/available-identities`, {
|
||||
params: {
|
||||
offset: params.offset,
|
||||
limit: params.limit,
|
||||
identityName: params.identityName
|
||||
}
|
||||
});
|
||||
return data.identities;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
// TODO (scott/akhi): move to new projectIdentityMembershipQuery structure
|
||||
|
||||
export const useListProjectIdentityMemberships = (
|
||||
{
|
||||
projectId,
|
||||
offset = 0,
|
||||
limit = 100,
|
||||
orderBy = ProjectIdentityOrderBy.Name,
|
||||
orderDirection = OrderByDirection.ASC,
|
||||
search = ""
|
||||
}: TListProjectIdentitiesDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TProjectIdentityMembershipsListV2,
|
||||
unknown,
|
||||
TProjectIdentityMembershipsListV2,
|
||||
ReturnType<typeof projectKeys.getProjectIdentityMembershipsWithParams>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipsWithParams({
|
||||
projectId,
|
||||
offset,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
search
|
||||
}),
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams({
|
||||
offset: String(offset),
|
||||
limit: String(limit),
|
||||
orderBy: String(orderBy),
|
||||
orderDirection: String(orderDirection),
|
||||
search: String(search)
|
||||
});
|
||||
|
||||
const { data } = await apiRequest.get<TProjectIdentityMembershipsListV2>(
|
||||
`/api/v1/projects/${projectId}/memberships/identities`,
|
||||
{ params }
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled: true,
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetProjectIdentityMembership = (projectId: string, identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && identityId),
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.get<{ identityMembership: IdentityProjectMembershipV1 }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetProjectIdentityMembershipV2 = (projectId: string, identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && identityId),
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetailsV2(projectId, identityId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.get<{ identityMembership: IdentityProjectMembershipV1 }>(
|
||||
`/api/v1/projects/${projectId}/memberships/identities/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { TRoles } from "@app/hooks/api/shared";
|
||||
|
||||
export type TProjectIdentityMembership = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
identityId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
// TODO
|
||||
};
|
||||
|
||||
export type TCreateProjectIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
role?: string;
|
||||
};
|
||||
|
||||
export type TUpdateProjectIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
roles: TRoles;
|
||||
};
|
||||
|
||||
export type TDeleteProjectIdentityMembershipDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TListAvailableProjectIdentitiesDTO = {
|
||||
projectId: string;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
identityName?: string;
|
||||
};
|
||||
|
||||
export type TAvailableProjectIdentities = Array<{ id: string; name: string }>;
|
||||
@@ -8,10 +8,8 @@ export {
|
||||
useUpdateProjectSshConfig
|
||||
} from "./mutations";
|
||||
export {
|
||||
useAddIdentityToWorkspace,
|
||||
useCreateWorkspace,
|
||||
useCreateWsEnvironment,
|
||||
useDeleteIdentityFromWorkspace,
|
||||
useDeleteUserFromWorkspace,
|
||||
useDeleteWorkspace,
|
||||
useDeleteWsEnvironment,
|
||||
@@ -21,8 +19,6 @@ export {
|
||||
useGetUserWorkspaceMemberships,
|
||||
useGetWorkspaceAuthorizations,
|
||||
useGetWorkspaceById,
|
||||
useGetWorkspaceIdentityMembershipDetails,
|
||||
useGetWorkspaceIdentityMemberships,
|
||||
useGetWorkspaceIndexStatus,
|
||||
useGetWorkspaceIntegrations,
|
||||
useGetWorkspaceUserDetails,
|
||||
@@ -41,7 +37,6 @@ export {
|
||||
useListWorkspaceSshHostGroups,
|
||||
useListWorkspaceSshHosts,
|
||||
useSearchProjects,
|
||||
useUpdateIdentityWorkspaceRole,
|
||||
useUpdateProject,
|
||||
useUpdateUserWorkspaceRole,
|
||||
useUpdateWsEnvironment,
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useMutation, useQuery, useQueryClient, UseQueryOptions } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
|
||||
import { CaStatus } from "../ca/enums";
|
||||
import { TCertificateAuthority } from "../ca/types";
|
||||
import { TCertificate } from "../certificates/types";
|
||||
import { TCertificateTemplate } from "../certificateTemplates/types";
|
||||
import { TGroupMembership } from "../groups/types";
|
||||
import { identitiesKeys } from "../identities/queries";
|
||||
import { IdentityMembership, TProjectIdentitiesList } from "../identities/types";
|
||||
import { IntegrationAuth } from "../integrationAuth/types";
|
||||
import { TIntegration } from "../integrations/types";
|
||||
import { TPkiAlert } from "../pkiAlerts/types";
|
||||
@@ -33,13 +30,10 @@ import {
|
||||
DeleteWorkspaceDTO,
|
||||
Project,
|
||||
ProjectEnv,
|
||||
ProjectIdentityOrderBy,
|
||||
ProjectType,
|
||||
TGetUpgradeProjectStatusDTO,
|
||||
TListProjectIdentitiesDTO,
|
||||
TProjectSshConfig,
|
||||
TSearchProjectsDTO,
|
||||
TUpdateWorkspaceIdentityRoleDTO,
|
||||
TUpdateWorkspaceUserRoleDTO,
|
||||
UpdateAuditLogsRetentionDTO,
|
||||
UpdateEnvironmentDTO,
|
||||
@@ -452,154 +446,6 @@ export const useUpdateUserWorkspaceRole = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAddIdentityToWorkspace = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
identityId,
|
||||
projectId,
|
||||
role
|
||||
}: {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
role?: string;
|
||||
}) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.post(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`,
|
||||
{
|
||||
role
|
||||
}
|
||||
);
|
||||
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateIdentityWorkspaceRole = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId, roles }: TUpdateWorkspaceIdentityRoleDTO) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.patch(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`,
|
||||
{
|
||||
roles
|
||||
}
|
||||
);
|
||||
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteIdentityFromWorkspace = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ identityId, projectId }: { identityId: string; projectId: string }) => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.delete(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
},
|
||||
onSuccess: (_, { identityId, projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectIdentityMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: identitiesKeys.getIdentityProjectMemberships(identityId)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetWorkspaceIdentityMemberships = (
|
||||
{
|
||||
projectId,
|
||||
offset = 0,
|
||||
limit = 100,
|
||||
orderBy = ProjectIdentityOrderBy.Name,
|
||||
orderDirection = OrderByDirection.ASC,
|
||||
search = ""
|
||||
}: TListProjectIdentitiesDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TProjectIdentitiesList,
|
||||
unknown,
|
||||
TProjectIdentitiesList,
|
||||
ReturnType<typeof projectKeys.getProjectIdentityMembershipsWithParams>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: projectKeys.getProjectIdentityMembershipsWithParams({
|
||||
projectId,
|
||||
offset,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
search
|
||||
}),
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams({
|
||||
offset: String(offset),
|
||||
limit: String(limit),
|
||||
orderBy: String(orderBy),
|
||||
orderDirection: String(orderDirection),
|
||||
search: String(search)
|
||||
});
|
||||
|
||||
const { data } = await apiRequest.get<TProjectIdentitiesList>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships`,
|
||||
{ params }
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled: true,
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetWorkspaceIdentityMembershipDetails = (projectId: string, identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && identityId),
|
||||
queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityMembership }
|
||||
} = await apiRequest.get<{ identityMembership: IdentityMembership }>(
|
||||
`/api/v1/projects/${projectId}/identity-memberships/${identityId}`
|
||||
);
|
||||
return identityMembership;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetWorkspaceGroupMembershipDetails = (projectId: string, groupId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(projectId && groupId),
|
||||
|
||||
@@ -23,6 +23,8 @@ export const projectKeys = {
|
||||
[{ projectId }, "project-identity-memberships"] as const,
|
||||
getProjectIdentityMembershipDetails: (projectId: string, identityId: string) =>
|
||||
[{ projectId, identityId }, "project-identity-membership-details"] as const,
|
||||
getProjectIdentityMembershipDetailsV2: (projectId: string, identityId: string) =>
|
||||
[{ projectId, identityId }, "project-identity-membership-details"] as const,
|
||||
// allows invalidation using above key without knowing params
|
||||
getProjectIdentityMembershipsWithParams: ({ projectId, ...params }: TListProjectIdentitiesDTO) =>
|
||||
[...projectKeys.getProjectIdentityMemberships(projectId), params] as const,
|
||||
|
||||
@@ -138,24 +138,6 @@ export type TUpdateWorkspaceUserRoleDTO = {
|
||||
)[];
|
||||
};
|
||||
|
||||
export type TUpdateWorkspaceIdentityRoleDTO = {
|
||||
identityId: string;
|
||||
projectId: string;
|
||||
roles: (
|
||||
| {
|
||||
role: string;
|
||||
isTemporary?: false;
|
||||
}
|
||||
| {
|
||||
role: string;
|
||||
isTemporary: true;
|
||||
temporaryMode: ProjectUserMembershipTemporaryMode;
|
||||
temporaryRange: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
)[];
|
||||
};
|
||||
|
||||
export type TUpdateWorkspaceGroupRoleDTO = {
|
||||
groupId: string;
|
||||
projectId: string;
|
||||
|
||||
@@ -59,6 +59,8 @@ export type TViewSharedSecretResponse = {
|
||||
tag: string;
|
||||
accessType: SecretSharingAccessType;
|
||||
orgName?: string;
|
||||
expiresAt?: Date | string;
|
||||
expiresAfterViews?: number | null;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,37 @@
|
||||
import { IdentityAuthMethod } from "@app/hooks/api";
|
||||
|
||||
export enum TemporaryPermissionMode {
|
||||
Relative = "relative"
|
||||
}
|
||||
|
||||
export type TMetadata = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type TIdentity = {
|
||||
id: string;
|
||||
name: string;
|
||||
orgId: string;
|
||||
projectId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
hasDeleteProtection: boolean;
|
||||
authMethods: IdentityAuthMethod[];
|
||||
activeLockoutAuthMethods: string[];
|
||||
metadata?: Array<TMetadata & { id: string }>;
|
||||
};
|
||||
|
||||
export type TRoles = Array<
|
||||
| {
|
||||
role: string;
|
||||
isTemporary?: false;
|
||||
}
|
||||
| {
|
||||
role: string;
|
||||
isTemporary: true;
|
||||
temporaryMode: TemporaryPermissionMode;
|
||||
temporaryRange: string;
|
||||
temporaryAccessStartTime: string;
|
||||
}
|
||||
>;
|
||||
@@ -7,7 +7,8 @@ import { SubscriptionPlan } from "./types";
|
||||
// import { Workspace } from './types';
|
||||
|
||||
export const subscriptionQueryKeys = {
|
||||
getOrgSubsription: (orgID: string) => ["plan", { orgID }] as const
|
||||
all: () => ["plan"] as const,
|
||||
getOrgSubsription: (orgID: string) => [...subscriptionQueryKeys.all(), { orgID }] as const
|
||||
};
|
||||
|
||||
export const fetchOrgSubscription = async (orgID: string, refreshCache: boolean = false) => {
|
||||
|
||||
@@ -48,6 +48,7 @@ export type SubscriptionPlan = {
|
||||
gateway: boolean;
|
||||
externalKms: boolean;
|
||||
pkiEst: boolean;
|
||||
pkiAcme: boolean;
|
||||
pkiLegacyTemplates: boolean;
|
||||
enforceMfa: boolean;
|
||||
enforceGoogleSSO: boolean;
|
||||
|
||||
@@ -2,12 +2,13 @@ import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { Button } from "@app/components/v2";
|
||||
import { useProject, useProjectPermission } from "@app/context";
|
||||
import { useOrganization, useProject, useProjectPermission } from "@app/context";
|
||||
import { getProjectHomePage } from "@app/helpers/project";
|
||||
import { useRemoveAssumeProjectPrivilege } from "@app/hooks/api";
|
||||
import { ActorType } from "@app/hooks/api/auditLogs/enums";
|
||||
|
||||
export const AssumePrivilegeModeBanner = () => {
|
||||
const { isSubOrganization, currentOrg } = useOrganization();
|
||||
const { currentProject } = useProject();
|
||||
const exitAssumePrivilegeMode = useRemoveAssumeProjectPrivilege();
|
||||
const { assumedPrivilegeDetails } = useProjectPermission();
|
||||
@@ -36,7 +37,7 @@ export const AssumePrivilegeModeBanner = () => {
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
const url = getProjectHomePage(currentProject.type, currentProject.environments);
|
||||
const url = `${getProjectHomePage(currentProject.type, currentProject.environments)}${isSubOrganization ? `?subOrganization=${currentOrg.slug}` : ""}`;
|
||||
window.location.href = url.replace("$projectId", currentProject.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState } from "react";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, DeleteActionModal } from "@app/components/v2";
|
||||
import { useProjectPermission } from "@app/context";
|
||||
@@ -9,6 +10,7 @@ import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context/ProjectPermissionContext/types";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import {
|
||||
TCertificateProfileWithDetails,
|
||||
useDeleteCertificateProfile
|
||||
@@ -29,6 +31,7 @@ export const CertificateProfilesTab = () => {
|
||||
const [selectedProfile, setSelectedProfile] = useState<TCertificateProfileWithDetails | null>(
|
||||
null
|
||||
);
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const);
|
||||
|
||||
const deleteProfile = useDeleteCertificateProfile();
|
||||
|
||||
@@ -99,7 +102,17 @@ export const CertificateProfilesTab = () => {
|
||||
onDeleteProfile={handleDeleteProfile}
|
||||
/>
|
||||
|
||||
<CreateProfileModal isOpen={isCreateModalOpen} onClose={() => setIsCreateModalOpen(false)} />
|
||||
<CreateProfileModal
|
||||
isOpen={isCreateModalOpen}
|
||||
onClose={() => setIsCreateModalOpen(false)}
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
/>
|
||||
<UpgradePlanModal
|
||||
isOpen={popUp.upgradePlan.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
|
||||
text="Your current plan does not include access to managing template enrollment options for ACME. To unlock this feature, please upgrade to Infisical Enterprise plan."
|
||||
/>
|
||||
|
||||
{selectedProfile && (
|
||||
<>
|
||||
@@ -109,6 +122,7 @@ export const CertificateProfilesTab = () => {
|
||||
setIsEditModalOpen(false);
|
||||
setSelectedProfile(null);
|
||||
}}
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
profile={selectedProfile}
|
||||
mode="edit"
|
||||
/>
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
TextArea,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { envConfig } from "@app/config/env";
|
||||
import { useProject } from "@app/context";
|
||||
import { useProject, useSubscription } from "@app/context";
|
||||
import { useListCasByProjectId } from "@app/hooks/api/ca/queries";
|
||||
import {
|
||||
TCertificateProfileWithDetails,
|
||||
@@ -29,6 +28,7 @@ import {
|
||||
useUpdateCertificateProfile
|
||||
} from "@app/hooks/api/certificateProfiles";
|
||||
import { useListCertificateTemplatesV2 } from "@app/hooks/api/certificateTemplates/queries";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const createSchema = z
|
||||
.object({
|
||||
@@ -151,12 +151,25 @@ export type FormData = z.infer<typeof createSchema>;
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["upgradePlan"]>,
|
||||
data?: {
|
||||
isEnterpriseFeature?: boolean;
|
||||
}
|
||||
) => void;
|
||||
profile?: TCertificateProfileWithDetails;
|
||||
mode?: "create" | "edit";
|
||||
}
|
||||
|
||||
export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" }: Props) => {
|
||||
export const CreateProfileModal = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
handlePopUpOpen,
|
||||
profile,
|
||||
mode = "create"
|
||||
}: Props) => {
|
||||
const { currentProject } = useProject();
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { data: caData } = useListCasByProjectId(currentProject?.id || "");
|
||||
const { data: templateData } = useListCertificateTemplatesV2({
|
||||
@@ -248,6 +261,15 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" }
|
||||
}, [isEdit, profile, reset]);
|
||||
|
||||
const onFormSubmit = async (data: FormData) => {
|
||||
if (!isEdit && !subscription?.pkiAcme && data.enrollmentType === "acme") {
|
||||
reset();
|
||||
onClose();
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
isEnterpriseFeature: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentProject?.id && !isEdit) return;
|
||||
|
||||
if (isEdit) {
|
||||
@@ -467,7 +489,7 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" }
|
||||
>
|
||||
<SelectItem value="api">API</SelectItem>
|
||||
<SelectItem value="est">EST</SelectItem>
|
||||
{envConfig.ACME_FEATURE_ENABLED && <SelectItem value="acme">ACME</SelectItem>}
|
||||
<SelectItem value="acme">ACME</SelectItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
ProjectPermissionSub
|
||||
} from "@app/context/ProjectPermissionContext/types";
|
||||
import { useDeleteCertificateTemplateV2WithPolicies } from "@app/hooks/api/certificateTemplates/mutations";
|
||||
import { TCertificateTemplateV2WithPolicies } from "@app/hooks/api/certificateTemplates/types";
|
||||
import { type TCertificateTemplateV2WithPolicies } from "@app/hooks/api/certificateTemplates/types";
|
||||
|
||||
import { CreateTemplateModal } from "./CreateTemplateModal";
|
||||
import { TemplateList } from "./TemplateList";
|
||||
@@ -84,7 +84,12 @@ export const CertificateTemplatesV2Tab = () => {
|
||||
|
||||
<TemplateList onEditTemplate={handleEditTemplate} onDeleteTemplate={handleDeleteTemplate} />
|
||||
|
||||
<CreateTemplateModal isOpen={isCreateModalOpen} onClose={() => setIsCreateModalOpen(false)} />
|
||||
<CreateTemplateModal
|
||||
isOpen={isCreateModalOpen}
|
||||
onClose={() => {
|
||||
setIsCreateModalOpen(false);
|
||||
}}
|
||||
/>
|
||||
|
||||
{selectedTemplate && (
|
||||
<>
|
||||
|
||||
@@ -36,13 +36,18 @@ import {
|
||||
CertDurationUnit,
|
||||
CertExtendedKeyUsageType,
|
||||
CertKeyUsageType,
|
||||
CertSanInclude,
|
||||
CertSubjectAlternativeNameType,
|
||||
CertSubjectAttributeInclude,
|
||||
CertSubjectAttributeType,
|
||||
SAN_INCLUDE_OPTIONS,
|
||||
SAN_TYPE_OPTIONS,
|
||||
SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS,
|
||||
SUBJECT_ATTRIBUTE_TYPE_OPTIONS
|
||||
SUBJECT_ATTRIBUTE_TYPE_OPTIONS,
|
||||
TEMPLATE_PRESET_IDS,
|
||||
type TemplatePresetId
|
||||
} from "./shared/certificate-constants";
|
||||
import { CERTIFICATE_TEMPLATE_PRESETS } from "./shared/template-presets";
|
||||
import { KeyUsagesSection, TemplateFormData, templateSchema } from "./shared";
|
||||
|
||||
export type FormData = TemplateFormData;
|
||||
@@ -91,7 +96,7 @@ const SIGNATURE_ALGORITHMS = [
|
||||
"SHA256-ECDSA",
|
||||
"SHA384-ECDSA",
|
||||
"SHA512-ECDSA"
|
||||
];
|
||||
] as const;
|
||||
|
||||
const KEY_ALGORITHMS = [
|
||||
"RSA-2048",
|
||||
@@ -100,7 +105,7 @@ const KEY_ALGORITHMS = [
|
||||
"ECDSA-P256",
|
||||
"ECDSA-P384",
|
||||
"ECDSA-P521"
|
||||
];
|
||||
] as const;
|
||||
|
||||
export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create" }: Props) => {
|
||||
const { currentProject } = useProject();
|
||||
@@ -117,7 +122,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
subj.allowed.forEach((allowedValue) => {
|
||||
attributes.push({
|
||||
type: subj.type as CertSubjectAttributeType,
|
||||
include: "optional",
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: [allowedValue]
|
||||
});
|
||||
});
|
||||
@@ -126,7 +131,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
subj.denied.forEach((deniedValue) => {
|
||||
attributes.push({
|
||||
type: subj.type as CertSubjectAttributeType,
|
||||
include: "prohibit",
|
||||
include: CertSubjectAttributeInclude.PROHIBIT,
|
||||
value: [deniedValue]
|
||||
});
|
||||
});
|
||||
@@ -141,7 +146,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
san.required.forEach((requiredValue) => {
|
||||
subjectAlternativeNames.push({
|
||||
type: san.type as CertSubjectAlternativeNameType,
|
||||
include: "mandatory",
|
||||
include: CertSanInclude.MANDATORY,
|
||||
value: [requiredValue]
|
||||
});
|
||||
});
|
||||
@@ -150,7 +155,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
san.allowed.forEach((allowedValue) => {
|
||||
subjectAlternativeNames.push({
|
||||
type: san.type as CertSubjectAlternativeNameType,
|
||||
include: "optional",
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: [allowedValue]
|
||||
});
|
||||
});
|
||||
@@ -159,7 +164,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
san.denied.forEach((deniedValue) => {
|
||||
subjectAlternativeNames.push({
|
||||
type: san.type as CertSubjectAlternativeNameType,
|
||||
include: "prohibit",
|
||||
include: CertSanInclude.PROHIBIT,
|
||||
value: [deniedValue]
|
||||
});
|
||||
});
|
||||
@@ -219,6 +224,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
};
|
||||
|
||||
return {
|
||||
preset: TEMPLATE_PRESET_IDS.CUSTOM,
|
||||
name: templateData.name || "",
|
||||
description: templateData.description || "",
|
||||
attributes,
|
||||
@@ -231,25 +237,30 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
};
|
||||
};
|
||||
|
||||
const getDefaultValues = (): FormData => ({
|
||||
name: "",
|
||||
description: "",
|
||||
attributes: [],
|
||||
keyUsages: { requiredUsages: [], optionalUsages: [] },
|
||||
extendedKeyUsages: { requiredUsages: [], optionalUsages: [] },
|
||||
subjectAlternativeNames: [],
|
||||
validity: {
|
||||
maxDuration: { value: 365, unit: CertDurationUnit.DAYS }
|
||||
},
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: []
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: []
|
||||
}
|
||||
});
|
||||
const getDefaultValues = (): FormData & { preset: TemplatePresetId } => {
|
||||
return {
|
||||
preset: TEMPLATE_PRESET_IDS.CUSTOM,
|
||||
name: "",
|
||||
description: "",
|
||||
attributes: [],
|
||||
keyUsages: { requiredUsages: [], optionalUsages: [] },
|
||||
extendedKeyUsages: { requiredUsages: [], optionalUsages: [] },
|
||||
subjectAlternativeNames: [],
|
||||
validity: {
|
||||
maxDuration: { value: 365, unit: CertDurationUnit.DAYS }
|
||||
},
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: []
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: []
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const { control, handleSubmit, reset, watch, setValue, formState } = useForm<FormData>({
|
||||
const { control, handleSubmit, reset, watch, setValue, formState } = useForm<
|
||||
FormData & { preset: TemplatePresetId }
|
||||
>({
|
||||
resolver: zodResolver(templateSchema),
|
||||
defaultValues: getDefaultValues(),
|
||||
mode: "onChange",
|
||||
@@ -260,7 +271,7 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
useEffect(() => {
|
||||
if (isEdit && template) {
|
||||
const convertedData = convertApiToUiFormat(template);
|
||||
reset(convertedData);
|
||||
reset({ ...convertedData, preset: TEMPLATE_PRESET_IDS.CUSTOM });
|
||||
} else if (!isEdit) {
|
||||
reset(getDefaultValues());
|
||||
}
|
||||
@@ -273,6 +284,37 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
requiredUsages: [],
|
||||
optionalUsages: []
|
||||
};
|
||||
const watchedPreset = watch("preset") || TEMPLATE_PRESET_IDS.CUSTOM;
|
||||
|
||||
const handlePresetChange = (presetId: TemplatePresetId) => {
|
||||
setValue("preset", presetId);
|
||||
|
||||
if (presetId === TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedPreset = CERTIFICATE_TEMPLATE_PRESETS.find((p) => p.id === presetId);
|
||||
if (selectedPreset) {
|
||||
if (selectedPreset.formData.keyUsages) {
|
||||
setValue("keyUsages", selectedPreset.formData.keyUsages);
|
||||
}
|
||||
if (selectedPreset.formData.extendedKeyUsages) {
|
||||
setValue("extendedKeyUsages", selectedPreset.formData.extendedKeyUsages);
|
||||
}
|
||||
if (selectedPreset.formData.attributes) {
|
||||
setValue("attributes", selectedPreset.formData.attributes);
|
||||
}
|
||||
if (selectedPreset.formData.subjectAlternativeNames) {
|
||||
setValue("subjectAlternativeNames", selectedPreset.formData.subjectAlternativeNames);
|
||||
}
|
||||
if (selectedPreset.formData.signatureAlgorithm) {
|
||||
setValue("signatureAlgorithm", selectedPreset.formData.signatureAlgorithm);
|
||||
}
|
||||
if (selectedPreset.formData.keyAlgorithm) {
|
||||
setValue("keyAlgorithm", selectedPreset.formData.keyAlgorithm);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const consolidateByType = <
|
||||
T extends { type: string; allowed?: string[]; required?: string[]; denied?: string[] }
|
||||
@@ -309,9 +351,17 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
data.attributes?.map((attr) => {
|
||||
const result: AttributeTransform = { type: attr.type };
|
||||
|
||||
if (attr.include === "optional" && attr.value && attr.value.length > 0) {
|
||||
if (
|
||||
attr.include === CertSubjectAttributeInclude.OPTIONAL &&
|
||||
attr.value &&
|
||||
attr.value.length > 0
|
||||
) {
|
||||
result.allowed = attr.value;
|
||||
} else if (attr.include === "prohibit" && attr.value && attr.value.length > 0) {
|
||||
} else if (
|
||||
attr.include === CertSubjectAttributeInclude.PROHIBIT &&
|
||||
attr.value &&
|
||||
attr.value.length > 0
|
||||
) {
|
||||
result.denied = attr.value;
|
||||
}
|
||||
|
||||
@@ -322,11 +372,11 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
data.subjectAlternativeNames?.map((san) => {
|
||||
const result: SanTransform = { type: san.type };
|
||||
|
||||
if (san.include === "mandatory" && san.value && san.value.length > 0) {
|
||||
if (san.include === CertSanInclude.MANDATORY && san.value && san.value.length > 0) {
|
||||
result.required = san.value;
|
||||
} else if (san.include === "optional" && san.value && san.value.length > 0) {
|
||||
} else if (san.include === CertSanInclude.OPTIONAL && san.value && san.value.length > 0) {
|
||||
result.allowed = san.value;
|
||||
} else if (san.include === "prohibit" && san.value && san.value.length > 0) {
|
||||
} else if (san.include === CertSanInclude.PROHIBIT && san.value && san.value.length > 0) {
|
||||
result.denied = san.value;
|
||||
}
|
||||
|
||||
@@ -464,11 +514,19 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
value: ["*"]
|
||||
};
|
||||
setValue("attributes", [...watchedAttributes, newAttribute]);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
};
|
||||
|
||||
const removeAttribute = (index: number) => {
|
||||
const newAttributes = watchedAttributes.filter((_, i) => i !== index);
|
||||
setValue("attributes", newAttributes);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
};
|
||||
|
||||
const addSan = () => {
|
||||
@@ -478,11 +536,19 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
value: ["*"]
|
||||
};
|
||||
setValue("subjectAlternativeNames", [...watchedSans, newSan]);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
};
|
||||
|
||||
const removeSan = (index: number) => {
|
||||
const newSans = watchedSans.filter((_, i) => i !== index);
|
||||
setValue("subjectAlternativeNames", newSans);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyUsagesChange = (usages: {
|
||||
@@ -493,6 +559,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
requiredUsages: usages.requiredUsages,
|
||||
optionalUsages: usages.optionalUsages
|
||||
});
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
};
|
||||
|
||||
const handleExtendedKeyUsagesChange = (usages: {
|
||||
@@ -503,6 +573,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
requiredUsages: usages.requiredUsages,
|
||||
optionalUsages: usages.optionalUsages
|
||||
});
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -555,6 +629,33 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="preset"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Template Preset"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={handlePresetChange}
|
||||
className="w-full"
|
||||
position="popper"
|
||||
dropdownContainerClassName="max-w-none"
|
||||
>
|
||||
<SelectItem value={TEMPLATE_PRESET_IDS.CUSTOM}>Custom</SelectItem>
|
||||
{CERTIFICATE_TEMPLATE_PRESETS.map((preset) => (
|
||||
<SelectItem key={preset.id} value={preset.id}>
|
||||
{preset.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<AccordionItem value="attributes">
|
||||
<AccordionTrigger>Subject Attributes</AccordionTrigger>
|
||||
@@ -595,6 +696,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
type: value as CertSubjectAttributeType
|
||||
};
|
||||
setValue("attributes", newAttributes);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
}}
|
||||
className="w-48"
|
||||
>
|
||||
@@ -615,6 +720,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
value as (typeof SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS)[number]
|
||||
};
|
||||
setValue("attributes", newAttributes);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
}}
|
||||
className="w-32"
|
||||
>
|
||||
@@ -635,6 +744,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
value: e.target.value.trim() ? [e.target.value.trim()] : []
|
||||
};
|
||||
setValue("attributes", newAttributes);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
}}
|
||||
className={`flex-1 ${
|
||||
attr.value && attr.value.length > 0 && attr.value[0] === ""
|
||||
@@ -701,6 +814,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
type: value as CertSubjectAlternativeNameType
|
||||
};
|
||||
setValue("subjectAlternativeNames", newSans);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
}}
|
||||
className="w-36"
|
||||
>
|
||||
@@ -720,6 +837,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
include: value as (typeof SAN_INCLUDE_OPTIONS)[number]
|
||||
};
|
||||
setValue("subjectAlternativeNames", newSans);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
}}
|
||||
className="w-32"
|
||||
>
|
||||
@@ -740,6 +861,10 @@ export const CreateTemplateModal = ({ isOpen, onClose, template, mode = "create"
|
||||
value: e.target.value.trim() ? [e.target.value.trim()] : []
|
||||
};
|
||||
setValue("subjectAlternativeNames", newSans);
|
||||
|
||||
if (watchedPreset !== TEMPLATE_PRESET_IDS.CUSTOM) {
|
||||
setValue("preset", TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
}
|
||||
}}
|
||||
className={`flex-1 ${
|
||||
san.value && san.value.length > 0 && san.value[0] === ""
|
||||
|
||||
@@ -150,8 +150,19 @@ export const SUBJECT_ATTRIBUTE_TYPE_OPTIONS = Object.values(CertSubjectAttribute
|
||||
export const ATTRIBUTE_RULE_OPTIONS = Object.values(CertAttributeRule);
|
||||
export const SAN_EFFECT_OPTIONS = Object.values(CertSanEffect);
|
||||
|
||||
export const SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS = ["optional", "prohibit"] as const;
|
||||
export const SAN_INCLUDE_OPTIONS = ["mandatory", "optional", "prohibit"] as const;
|
||||
export enum CertSubjectAttributeInclude {
|
||||
OPTIONAL = "optional",
|
||||
PROHIBIT = "prohibit"
|
||||
}
|
||||
|
||||
export enum CertSanInclude {
|
||||
MANDATORY = "mandatory",
|
||||
OPTIONAL = "optional",
|
||||
PROHIBIT = "prohibit"
|
||||
}
|
||||
|
||||
export const SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS = Object.values(CertSubjectAttributeInclude);
|
||||
export const SAN_INCLUDE_OPTIONS = Object.values(CertSanInclude);
|
||||
|
||||
export const USAGE_STATES = {
|
||||
REQUIRED: "required",
|
||||
@@ -239,3 +250,27 @@ export const mapTemplateKeyAlgorithmToApi = (templateFormat: string): string =>
|
||||
};
|
||||
return mapping[templateFormat] || templateFormat;
|
||||
};
|
||||
|
||||
export const TEMPLATE_PRESET_IDS = {
|
||||
CUSTOM: "custom",
|
||||
TLS_SERVER: "tls-server",
|
||||
TLS_CLIENT: "tls-client",
|
||||
CODE_SIGNING: "code-signing",
|
||||
DEVICE: "device",
|
||||
USER: "user",
|
||||
EMAIL_PROTECTION: "email-protection",
|
||||
DUAL_PURPOSE_SERVER: "dual-purpose-server"
|
||||
} as const;
|
||||
|
||||
export type TemplatePresetId = (typeof TEMPLATE_PRESET_IDS)[keyof typeof TEMPLATE_PRESET_IDS];
|
||||
|
||||
export const ALGORITHM_FAMILIES = {
|
||||
ECDSA: {
|
||||
signature: ["SHA256-ECDSA", "SHA384-ECDSA", "SHA512-ECDSA"] as const,
|
||||
key: ["ECDSA-P256", "ECDSA-P384", "ECDSA-P521"] as const
|
||||
},
|
||||
RSA: {
|
||||
signature: ["SHA256-RSA", "SHA384-RSA", "SHA512-RSA"] as const,
|
||||
key: ["RSA-2048", "RSA-3072", "RSA-4096"] as const
|
||||
}
|
||||
} as const;
|
||||
|
||||
@@ -4,21 +4,22 @@ import {
|
||||
CertDurationUnit,
|
||||
CertExtendedKeyUsageType,
|
||||
CertKeyUsageType,
|
||||
CertSanInclude,
|
||||
CertSubjectAlternativeNameType,
|
||||
CertSubjectAttributeInclude,
|
||||
CertSubjectAttributeType,
|
||||
SAN_INCLUDE_OPTIONS,
|
||||
SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS
|
||||
TEMPLATE_PRESET_IDS
|
||||
} from "./certificate-constants";
|
||||
|
||||
export const uiAttributeSchema = z.object({
|
||||
type: z.nativeEnum(CertSubjectAttributeType),
|
||||
include: z.enum(SUBJECT_ATTRIBUTE_INCLUDE_OPTIONS),
|
||||
include: z.nativeEnum(CertSubjectAttributeInclude),
|
||||
value: z.array(z.string().min(1, "Value cannot be empty"))
|
||||
});
|
||||
|
||||
export const uiSanSchema = z.object({
|
||||
type: z.nativeEnum(CertSubjectAlternativeNameType),
|
||||
include: z.enum(SAN_INCLUDE_OPTIONS),
|
||||
include: z.nativeEnum(CertSanInclude),
|
||||
value: z.array(z.string().min(1, "Value cannot be empty"))
|
||||
});
|
||||
|
||||
@@ -51,7 +52,21 @@ export const uiKeyAlgorithmSchema = z.object({
|
||||
.min(1, "At least one key type must be selected")
|
||||
});
|
||||
|
||||
export const uiPresetSchema = z
|
||||
.enum([
|
||||
TEMPLATE_PRESET_IDS.CUSTOM,
|
||||
TEMPLATE_PRESET_IDS.TLS_SERVER,
|
||||
TEMPLATE_PRESET_IDS.TLS_CLIENT,
|
||||
TEMPLATE_PRESET_IDS.CODE_SIGNING,
|
||||
TEMPLATE_PRESET_IDS.DEVICE,
|
||||
TEMPLATE_PRESET_IDS.USER,
|
||||
TEMPLATE_PRESET_IDS.EMAIL_PROTECTION,
|
||||
TEMPLATE_PRESET_IDS.DUAL_PURPOSE_SERVER
|
||||
])
|
||||
.default(TEMPLATE_PRESET_IDS.CUSTOM);
|
||||
|
||||
export const templateSchema = z.object({
|
||||
preset: uiPresetSchema,
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
import {
|
||||
ALGORITHM_FAMILIES,
|
||||
CertDurationUnit,
|
||||
CertExtendedKeyUsageType,
|
||||
CertKeyUsageType,
|
||||
CertSanInclude,
|
||||
CertSubjectAlternativeNameType,
|
||||
CertSubjectAttributeInclude,
|
||||
CertSubjectAttributeType,
|
||||
TEMPLATE_PRESET_IDS,
|
||||
type TemplatePresetId
|
||||
} from "./certificate-constants";
|
||||
import { TemplateFormData } from ".";
|
||||
|
||||
export interface CertificateTemplatePreset {
|
||||
readonly id: TemplatePresetId;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly useCase: string;
|
||||
readonly formData: Omit<TemplateFormData, "preset">;
|
||||
}
|
||||
|
||||
export const CERTIFICATE_TEMPLATE_PRESETS: CertificateTemplatePreset[] = [
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.TLS_SERVER,
|
||||
name: "TLS Server Certificate",
|
||||
description: "Standard TLS/SSL server certificate for HTTPS services and API endpoints.",
|
||||
useCase: "Web servers, API endpoints, HTTPS services",
|
||||
formData: {
|
||||
name: "TLS Server Certificate",
|
||||
description: "Standard TLS/SSL server certificate for HTTPS services and API endpoints.",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
|
||||
optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.KEY_ENCIPHERMENT]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [CertExtendedKeyUsageType.SERVER_AUTH],
|
||||
optionalUsages: [CertExtendedKeyUsageType.SERVER_AUTH]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.DNS_NAME,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
},
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.IP_ADDRESS,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.TLS_CLIENT,
|
||||
name: "TLS Client Certificate",
|
||||
description: "Client certificate for mutual TLS authentication and API access.",
|
||||
useCase: "Client authentication, mTLS, API authentication",
|
||||
formData: {
|
||||
name: "TLS Client Certificate",
|
||||
description: "Client certificate for mutual TLS authentication and API access.",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
|
||||
optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.KEY_AGREEMENT]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [CertExtendedKeyUsageType.CLIENT_AUTH],
|
||||
optionalUsages: [CertExtendedKeyUsageType.CLIENT_AUTH]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.EMAIL,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
},
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.DNS_NAME,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.CODE_SIGNING,
|
||||
name: "Code Signing Certificate",
|
||||
description:
|
||||
"Certificate for signing software, executables, and packages. Requires hardware security modules.",
|
||||
useCase: "Software signing, executable authentication, package validation",
|
||||
formData: {
|
||||
name: "Code Signing Certificate",
|
||||
description:
|
||||
"Certificate for signing software, executables, and packages. Requires hardware security modules.",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.NON_REPUDIATION],
|
||||
optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.NON_REPUDIATION]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [CertExtendedKeyUsageType.CODE_SIGNING],
|
||||
optionalUsages: [
|
||||
CertExtendedKeyUsageType.CODE_SIGNING,
|
||||
CertExtendedKeyUsageType.TIME_STAMPING
|
||||
]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.EMAIL,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.RSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.RSA.key]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.DEVICE,
|
||||
name: "Device Certificate",
|
||||
description:
|
||||
"Certificate for IoT devices and embedded systems authentication. IEEE 802.1AR compliant.",
|
||||
useCase: "Device authentication, IoT security, embedded systems",
|
||||
formData: {
|
||||
name: "Device Certificate",
|
||||
description:
|
||||
"Certificate for IoT devices and embedded systems authentication. IEEE 802.1AR compliant.",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
|
||||
optionalUsages: [CertKeyUsageType.DIGITAL_SIGNATURE, CertKeyUsageType.KEY_AGREEMENT]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [CertExtendedKeyUsageType.CLIENT_AUTH],
|
||||
optionalUsages: [CertExtendedKeyUsageType.CLIENT_AUTH, CertExtendedKeyUsageType.SERVER_AUTH]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.DNS_NAME,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
},
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.IP_ADDRESS,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.USER,
|
||||
name: "User Certificate",
|
||||
description:
|
||||
"Personal certificate for user authentication and email signing. FIPS 201 PIV compliant.",
|
||||
useCase: "Personal authentication, smart cards, email protection",
|
||||
formData: {
|
||||
name: "User Certificate",
|
||||
description:
|
||||
"Personal certificate for user authentication and email signing. FIPS 201 PIV compliant.",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
|
||||
optionalUsages: [
|
||||
CertKeyUsageType.DIGITAL_SIGNATURE,
|
||||
CertKeyUsageType.KEY_ENCIPHERMENT,
|
||||
CertKeyUsageType.KEY_AGREEMENT
|
||||
]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [
|
||||
CertExtendedKeyUsageType.CLIENT_AUTH,
|
||||
CertExtendedKeyUsageType.EMAIL_PROTECTION
|
||||
],
|
||||
optionalUsages: [
|
||||
CertExtendedKeyUsageType.CLIENT_AUTH,
|
||||
CertExtendedKeyUsageType.EMAIL_PROTECTION
|
||||
]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.EMAIL,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.EMAIL_PROTECTION,
|
||||
name: "Email Protection Certificate",
|
||||
description: "S/MIME certificate for email encryption and digital signing. RFC 8550 compliant.",
|
||||
useCase: "Email encryption, digital signing, secure messaging",
|
||||
formData: {
|
||||
name: "Email Protection Certificate",
|
||||
description:
|
||||
"S/MIME certificate for email encryption and digital signing. RFC 8550 compliant.",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
|
||||
optionalUsages: [
|
||||
CertKeyUsageType.DIGITAL_SIGNATURE,
|
||||
CertKeyUsageType.KEY_ENCIPHERMENT,
|
||||
CertKeyUsageType.KEY_AGREEMENT
|
||||
]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [CertExtendedKeyUsageType.EMAIL_PROTECTION],
|
||||
optionalUsages: [CertExtendedKeyUsageType.EMAIL_PROTECTION]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.EMAIL,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.RSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.RSA.key]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: TEMPLATE_PRESET_IDS.DUAL_PURPOSE_SERVER,
|
||||
name: "Dual-Purpose Server Certificate",
|
||||
description:
|
||||
"Certificate for services requiring both server and client authentication capabilities",
|
||||
useCase: "Microservices, service mesh, dual authentication",
|
||||
formData: {
|
||||
name: "Dual-Purpose Server Certificate",
|
||||
description:
|
||||
"Certificate for services requiring both server and client authentication capabilities",
|
||||
keyUsages: {
|
||||
requiredUsages: [CertKeyUsageType.DIGITAL_SIGNATURE],
|
||||
optionalUsages: [
|
||||
CertKeyUsageType.DIGITAL_SIGNATURE,
|
||||
CertKeyUsageType.KEY_ENCIPHERMENT,
|
||||
CertKeyUsageType.KEY_AGREEMENT
|
||||
]
|
||||
},
|
||||
extendedKeyUsages: {
|
||||
requiredUsages: [
|
||||
CertExtendedKeyUsageType.SERVER_AUTH,
|
||||
CertExtendedKeyUsageType.CLIENT_AUTH
|
||||
],
|
||||
optionalUsages: [CertExtendedKeyUsageType.SERVER_AUTH, CertExtendedKeyUsageType.CLIENT_AUTH]
|
||||
},
|
||||
validity: {
|
||||
maxDuration: {
|
||||
value: 365,
|
||||
unit: CertDurationUnit.DAYS
|
||||
}
|
||||
},
|
||||
attributes: [
|
||||
{
|
||||
type: CertSubjectAttributeType.COMMON_NAME,
|
||||
include: CertSubjectAttributeInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
subjectAlternativeNames: [
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.DNS_NAME,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
},
|
||||
{
|
||||
type: CertSubjectAlternativeNameType.IP_ADDRESS,
|
||||
include: CertSanInclude.OPTIONAL,
|
||||
value: ["*"]
|
||||
}
|
||||
],
|
||||
signatureAlgorithm: {
|
||||
allowedAlgorithms: [...ALGORITHM_FAMILIES.ECDSA.signature]
|
||||
},
|
||||
keyAlgorithm: {
|
||||
allowedKeyTypes: [...ALGORITHM_FAMILIES.ECDSA.key]
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -76,7 +77,9 @@ export const IdentityAliCloudAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAliCloudAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAliCloudAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -144,7 +147,7 @@ export const IdentityAliCloudAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
allowedArns,
|
||||
identityId,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
@@ -154,7 +157,7 @@ export const IdentityAliCloudAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
allowedArns,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -78,7 +79,9 @@ export const IdentityAwsAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -154,7 +157,7 @@ export const IdentityAwsAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
allowedAccountIds,
|
||||
@@ -166,7 +169,7 @@ export const IdentityAwsAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
stsEndpoint: stsEndpoint || "",
|
||||
allowedPrincipalArns: allowedPrincipalArns || "",
|
||||
@@ -176,10 +179,8 @@ export const IdentityAwsAuthForm = ({
|
||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||
accessTokenTrustedIps
|
||||
});
|
||||
handlePopUpToggle("identityAuthMethod", false);
|
||||
}
|
||||
|
||||
handlePopUpToggle("identityAuthMethod", false);
|
||||
|
||||
createNotification({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -73,7 +74,9 @@ export const IdentityAzureAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAzureAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAzureAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -150,7 +153,7 @@ export const IdentityAzureAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
tenantId,
|
||||
resource,
|
||||
@@ -162,7 +165,7 @@ export const IdentityAzureAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
tenantId: tenantId || "",
|
||||
resource: resource || "",
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -76,7 +77,9 @@ export const IdentityGcpAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityGcpAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityGcpAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -160,7 +163,7 @@ export const IdentityGcpAuthForm = ({
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
type,
|
||||
allowedServiceAccounts,
|
||||
allowedProjects,
|
||||
@@ -173,7 +176,7 @@ export const IdentityGcpAuthForm = ({
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
type,
|
||||
allowedServiceAccounts: allowedServiceAccounts || "",
|
||||
allowedProjects: allowedProjects || "",
|
||||
@@ -191,7 +194,6 @@ export const IdentityGcpAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -109,7 +110,9 @@ export const IdentityJwtAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityJwtAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityJwtAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -227,7 +230,7 @@ export const IdentityJwtAuthForm = ({
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
configurationType,
|
||||
jwksUrl,
|
||||
jwksCaCert,
|
||||
@@ -252,7 +255,7 @@ export const IdentityJwtAuthForm = ({
|
||||
boundAudiences,
|
||||
boundClaims: Object.fromEntries(boundClaims.map((entry) => [entry.key, entry.value])),
|
||||
boundSubject,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||
@@ -266,7 +269,6 @@ export const IdentityJwtAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { faInfoCircle, faPlus, faXmark } from "@fortawesome/free-solid-svg-icons
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -117,7 +118,9 @@ export const IdentityKubernetesAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityKubernetesAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityKubernetesAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -318,7 +321,7 @@ export const IdentityKubernetesAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
...(tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Api
|
||||
? {
|
||||
kubernetesHost: kubernetesHost || ""
|
||||
@@ -341,7 +344,7 @@ export const IdentityKubernetesAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
...(tokenReviewMode === IdentityKubernetesAuthTokenReviewMode.Api
|
||||
? {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faQuestionCircle, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import ms from "ms";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -168,7 +169,9 @@ export const IdentityLdapAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityLdapAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityLdapAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -345,7 +348,7 @@ export const IdentityLdapAuthForm = ({
|
||||
ms(`${lockoutCounterResetValue}${lockoutCounterResetUnit}`) / 1000;
|
||||
|
||||
const basePayload = {
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
searchFilter,
|
||||
ldapCaCertificate,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -84,7 +85,9 @@ export const IdentityOciAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityOciAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityOciAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -156,7 +159,7 @@ export const IdentityOciAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
tenancyOcid,
|
||||
allowedUsernames,
|
||||
identityId,
|
||||
@@ -167,7 +170,7 @@ export const IdentityOciAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
tenancyOcid,
|
||||
allowedUsernames: allowedUsernames || undefined,
|
||||
@@ -184,7 +187,6 @@ export const IdentityOciAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { faQuestionCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -96,7 +97,9 @@ export const IdentityOidcAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityOidcAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityOidcAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -211,7 +214,7 @@ export const IdentityOidcAuthForm = ({
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
oidcDiscoveryUrl,
|
||||
caCert,
|
||||
boundIssuer,
|
||||
@@ -238,7 +241,7 @@ export const IdentityOidcAuthForm = ({
|
||||
? Object.fromEntries(claimMetadataMapping.map((entry) => [entry.key, entry.value]))
|
||||
: undefined,
|
||||
boundSubject,
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||
@@ -252,7 +255,6 @@ export const IdentityOidcAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { faLink, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { useState } from "react";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { LinkIcon, PlusIcon } from "lucide-react";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -14,17 +17,23 @@ import {
|
||||
} from "@app/context";
|
||||
import { OrgPermissionMachineIdentityAuthTemplateActions } from "@app/context/OrgPermissionContext/types";
|
||||
import { withPermission } from "@app/hoc";
|
||||
import { useDeleteIdentity } from "@app/hooks/api";
|
||||
import { useDeleteOrgIdentity } from "@app/hooks/api";
|
||||
import { useDeleteIdentityAuthTemplate } from "@app/hooks/api/identityAuthTemplates";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { IdentityAuthTemplateModal } from "./IdentityAuthTemplateModal";
|
||||
import { IdentityAuthTemplatesTable } from "./IdentityAuthTemplatesTable";
|
||||
import { IdentityLinkForm } from "./IdentityLinkForm";
|
||||
import { IdentityModal } from "./IdentityModal";
|
||||
import { IdentityTable } from "./IdentityTable";
|
||||
import { IdentityTokenAuthTokenModal } from "./IdentityTokenAuthTokenModal";
|
||||
import { MachineAuthTemplateUsagesModal } from "./MachineAuthTemplateUsagesModal";
|
||||
import { OrgIdentityLinkForm } from "./OrgIdentityLinkForm";
|
||||
import { OrgIdentityModal } from "./OrgIdentityModal";
|
||||
|
||||
enum IdentityWizardSteps {
|
||||
SelectAction = "select-action",
|
||||
LinkIdentity = "link-identity",
|
||||
OrganizationIdentity = "project-identity"
|
||||
}
|
||||
|
||||
export const IdentitySection = withPermission(
|
||||
() => {
|
||||
@@ -32,7 +41,9 @@ export const IdentitySection = withPermission(
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteIdentity();
|
||||
const [wizardStep, setWizardStep] = useState(IdentityWizardSteps.SelectAction);
|
||||
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteOrgIdentity();
|
||||
const { mutateAsync: deleteTemplateMutateAsync } = useDeleteIdentityAuthTemplate();
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"identity",
|
||||
@@ -46,7 +57,7 @@ export const IdentitySection = withPermission(
|
||||
"editTemplate",
|
||||
"deleteTemplate",
|
||||
"viewUsages",
|
||||
"linkIdentity"
|
||||
"addOptions"
|
||||
] as const);
|
||||
|
||||
const isMoreIdentitiesAllowed = subscription?.identityLimit
|
||||
@@ -58,7 +69,7 @@ export const IdentitySection = withPermission(
|
||||
const onDeleteIdentitySubmit = async (identityId: string) => {
|
||||
await deleteMutateAsync({
|
||||
identityId,
|
||||
organizationId: orgId
|
||||
orgId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
@@ -91,50 +102,38 @@ export const IdentitySection = withPermission(
|
||||
<p className="text-xl font-medium text-mineshaft-100">Identities</p>
|
||||
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
|
||||
</div>
|
||||
{isSubOrganization && (
|
||||
<div className="flex items-center">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Create}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
variant="plain"
|
||||
colorSchema="secondary"
|
||||
leftIcon={<FontAwesomeIcon icon={faLink} />}
|
||||
variant="outline_bg"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => {
|
||||
handlePopUpOpen("linkIdentity");
|
||||
if (!isMoreIdentitiesAllowed && !isEnterprise) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
description:
|
||||
"You can add more identities if you upgrade your Infisical Pro plan."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSubOrganization) {
|
||||
setWizardStep(IdentityWizardSteps.OrganizationIdentity);
|
||||
}
|
||||
|
||||
handlePopUpOpen("identity");
|
||||
}}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Link Identity
|
||||
Create Identity
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
)}
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Create}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => {
|
||||
if (!isMoreIdentitiesAllowed && !isEnterprise) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
text: "You have reached the maximum number of identities allowed on your current plan. Upgrade to Infisical Pro plan to add more identities."
|
||||
});
|
||||
return;
|
||||
}
|
||||
handlePopUpOpen("identity");
|
||||
}}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Create Identity
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</div>
|
||||
</div>
|
||||
<IdentityTable handlePopUpOpen={handlePopUpOpen} />
|
||||
</div>
|
||||
@@ -173,7 +172,6 @@ export const IdentitySection = withPermission(
|
||||
</div>
|
||||
<IdentityAuthTemplatesTable handlePopUpOpen={handlePopUpOpen} />
|
||||
</div>
|
||||
<IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<IdentityAuthTemplateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<MachineAuthTemplateUsagesModal
|
||||
isOpen={popUp.viewUsages.isOpen}
|
||||
@@ -187,19 +185,99 @@ export const IdentitySection = withPermission(
|
||||
?.name || ""
|
||||
}
|
||||
/>
|
||||
<IdentityTokenAuthTokenModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<Modal
|
||||
isOpen={popUp.linkIdentity.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("linkIdentity", isOpen)}
|
||||
isOpen={popUp.identity.isOpen}
|
||||
onOpenChange={(open) => {
|
||||
handlePopUpToggle("identity", open);
|
||||
if (!open) {
|
||||
setWizardStep(IdentityWizardSteps.SelectAction);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ModalContent
|
||||
title="Assign Existing Identity"
|
||||
subTitle="Assign an existing identity from your root organization to the sub organization. The identity will continue to be managed at its original scope."
|
||||
bodyClassName="overflow-visible"
|
||||
title="Add Identity"
|
||||
subTitle={
|
||||
isSubOrganization ? "Create a new identity or assign an existing identity" : undefined
|
||||
}
|
||||
>
|
||||
<IdentityLinkForm onClose={() => handlePopUpClose("linkIdentity")} />
|
||||
<AnimatePresence mode="wait">
|
||||
{wizardStep === IdentityWizardSteps.SelectAction && (
|
||||
<motion.div
|
||||
key="select-type-step"
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: -30 }}
|
||||
>
|
||||
<div
|
||||
className="cursor-pointer rounded-md border border-mineshaft-600 p-4 transition-all hover:bg-mineshaft-700"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setWizardStep(IdentityWizardSteps.OrganizationIdentity)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
setWizardStep(IdentityWizardSteps.OrganizationIdentity);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<PlusIcon size="1rem" />
|
||||
<div>Create New Identity</div>
|
||||
</div>
|
||||
<div className="mt-2 text-xs text-mineshaft-300">
|
||||
Create a new machine identity specifically for this sub-organization. This
|
||||
identity will be managed at the sub-organization level.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="mt-4 cursor-pointer rounded-md border border-mineshaft-600 p-4 transition-all hover:bg-mineshaft-700"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setWizardStep(IdentityWizardSteps.LinkIdentity)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
setWizardStep(IdentityWizardSteps.LinkIdentity);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<LinkIcon size="1rem" />
|
||||
<div>Assign Existing Identity</div>
|
||||
</div>
|
||||
<div className="mt-2 text-xs text-mineshaft-300">
|
||||
Assign an existing identity from your parent organization. The identity will
|
||||
continue to be managed at its original scope.
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
{wizardStep === IdentityWizardSteps.OrganizationIdentity && (
|
||||
<motion.div
|
||||
key="identity-step"
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: -30 }}
|
||||
>
|
||||
<OrgIdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
</motion.div>
|
||||
)}
|
||||
{wizardStep === IdentityWizardSteps.LinkIdentity && (
|
||||
<motion.div
|
||||
key="link-step"
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: -30 }}
|
||||
>
|
||||
<OrgIdentityLinkForm onClose={() => handlePopUpClose("identity")} />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<IdentityTokenAuthTokenModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteIdentity.isOpen}
|
||||
title={`Are you sure you want to delete ${
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useCallback, useState } from "react";
|
||||
import {
|
||||
faArrowDown,
|
||||
faArrowUp,
|
||||
faBuilding,
|
||||
faCheckCircle,
|
||||
faChevronRight,
|
||||
faEdit,
|
||||
@@ -46,6 +45,7 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { Badge, OrgIcon, SubOrgIcon } from "@app/components/v3";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import {
|
||||
getUserTablePreference,
|
||||
@@ -56,8 +56,8 @@ import { usePagination, useResetPageHelper } from "@app/hooks";
|
||||
import {
|
||||
identityAuthToNameMap,
|
||||
useGetOrgRoles,
|
||||
useSearchIdentities,
|
||||
useUpdateIdentity
|
||||
useSearchOrgIdentityMemberships,
|
||||
useUpdateOrgIdentity
|
||||
} from "@app/hooks/api";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { OrgIdentityOrderBy } from "@app/hooks/api/organization/types";
|
||||
@@ -110,9 +110,9 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
|
||||
const organizationId = currentOrg?.id || "";
|
||||
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateOrgIdentity();
|
||||
|
||||
const { data, isPending, isFetching } = useSearchIdentities({
|
||||
const { data, isPending, isFetching } = useSearchOrgIdentityMemberships({
|
||||
offset,
|
||||
limit,
|
||||
orderDirection,
|
||||
@@ -293,6 +293,8 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
lastLoginAuthMethod,
|
||||
lastLoginTime
|
||||
}) => {
|
||||
const isSubOrgIdentity = currentOrg.id === orgId;
|
||||
|
||||
return (
|
||||
<Tr
|
||||
className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||
@@ -357,10 +359,19 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
</Td>
|
||||
{isSubOrganization && (
|
||||
<Td>
|
||||
<p className="truncate">
|
||||
<FontAwesomeIcon size="sm" className="mr-1.5" icon={faBuilding} />
|
||||
{currentOrg.id === orgId ? "Sub Organization" : "Root Organization"}
|
||||
</p>
|
||||
<Badge variant={isSubOrgIdentity ? "sub-org" : "org"}>
|
||||
{isSubOrgIdentity ? (
|
||||
<>
|
||||
<SubOrgIcon />
|
||||
Sub-Organization
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<OrgIcon />
|
||||
Root Organization
|
||||
</>
|
||||
)}
|
||||
</Badge>
|
||||
</Td>
|
||||
)}
|
||||
<Td>
|
||||
@@ -394,7 +405,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
}}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Edit Identity
|
||||
Edit Identity {isSubOrgIdentity ? "" : "Membership"}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
@@ -414,7 +425,9 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
|
||||
isDisabled={!isAllowed}
|
||||
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||
>
|
||||
Delete Identity
|
||||
{isSubOrgIdentity
|
||||
? "Delete Identity"
|
||||
: "Remove From Sub-Organization"}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -71,7 +72,9 @@ export const IdentityTlsCertAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityTlsCertAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityTlsCertAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -141,7 +144,7 @@ export const IdentityTlsCertAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
caCertificate,
|
||||
allowedCommonNames: allowedCommonNames || null,
|
||||
identityId,
|
||||
@@ -152,7 +155,7 @@ export const IdentityTlsCertAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
caCertificate,
|
||||
allowedCommonNames: allowedCommonNames || undefined,
|
||||
@@ -169,7 +172,6 @@ export const IdentityTlsCertAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "configured"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -70,7 +71,9 @@ export const IdentityTokenAuthForm = ({
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityTokenAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityTokenAuth();
|
||||
const [tabValue, setTabValue] = useState<IdentityFormTab>(IdentityFormTab.Configuration);
|
||||
@@ -134,7 +137,7 @@ export const IdentityTokenAuthForm = ({
|
||||
|
||||
if (data) {
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
@@ -143,7 +146,7 @@ export const IdentityTokenAuthForm = ({
|
||||
});
|
||||
} else {
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Controller, useFieldArray, useForm } from "react-hook-form";
|
||||
import { faPlus, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import ms from "ms";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -105,6 +106,9 @@ export const IdentityUniversalAuthForm = ({
|
||||
identityId,
|
||||
isUpdate
|
||||
}: Props) => {
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
@@ -232,7 +236,7 @@ export const IdentityUniversalAuthForm = ({
|
||||
if (data) {
|
||||
// update universal auth configuration
|
||||
await updateMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
clientSecretTrustedIps,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
@@ -249,7 +253,7 @@ export const IdentityUniversalAuthForm = ({
|
||||
// create new universal auth configuration
|
||||
|
||||
await addMutateAsync({
|
||||
organizationId: orgId,
|
||||
...(projectId ? { projectId } : { organizationId: orgId }),
|
||||
identityId,
|
||||
clientSecretTrustedIps,
|
||||
accessTokenTTL: Number(accessTokenTTL),
|
||||
@@ -270,7 +274,6 @@ export const IdentityUniversalAuthForm = ({
|
||||
text: `Successfully ${isUpdate ? "updated" : "created"} auth method`,
|
||||
type: "success"
|
||||
});
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FilterableSelect, FormControl } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { useGetAvailableOrgIdentities, useGetOrgRoles } from "@app/hooks/api";
|
||||
import { useGetOrgRoles } from "@app/hooks/api";
|
||||
import { useCreateOrgIdentityMembership } from "@app/hooks/api/orgIdentityMembership";
|
||||
import { orgIdentityMembershipQuery } from "@app/hooks/api/orgIdentityMembership/queries";
|
||||
|
||||
const schema = z
|
||||
.object({
|
||||
@@ -22,15 +24,26 @@ type Props = {
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export const IdentityLinkForm = ({ onClose }: Props) => {
|
||||
export const OrgIdentityLinkForm = ({ onClose }: Props) => {
|
||||
const navigate = useNavigate();
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
|
||||
const { data: roles } = useGetOrgRoles(orgId);
|
||||
|
||||
// const [searchValue, setSearchValue] = useState("");
|
||||
//
|
||||
// const [debouncedSearchValue] = useDebounce(searchValue);
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateOrgIdentityMembership();
|
||||
const { data: rootOrgIdentities, isPending: isRootOrgLoading } = useGetAvailableOrgIdentities();
|
||||
|
||||
// TODO: name filter needs to be implemented on backend
|
||||
const { data: rootOrgIdentities, isPending: isRootOrgLoading } = useQuery({
|
||||
...orgIdentityMembershipQuery.listAvailable({
|
||||
// identityName: debouncedSearchValue
|
||||
}),
|
||||
placeholderData: (prev) => prev
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -69,6 +82,7 @@ export const IdentityLinkForm = ({ onClose }: Props) => {
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
placeholder="Select identity..."
|
||||
// onInputChange={setSearchValue}
|
||||
options={rootOrgIdentities}
|
||||
getOptionValue={(option) => option.id}
|
||||
getOptionLabel={(option) => option.name}
|
||||
@@ -94,7 +108,6 @@ export const IdentityLinkForm = ({ onClose }: Props) => {
|
||||
placeholder="Select role..."
|
||||
getOptionValue={(option) => option.slug}
|
||||
getOptionLabel={(option) => option.name}
|
||||
// menuPortalTarget={document.body}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
@@ -14,13 +14,11 @@ import {
|
||||
FormLabel,
|
||||
IconButton,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Switch
|
||||
} from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { findOrgMembershipRole } from "@app/helpers/roles";
|
||||
import { useCreateIdentity, useGetOrgRoles, useUpdateIdentity } from "@app/hooks/api";
|
||||
import { useCreateOrgIdentity, useGetOrgRoles, useUpdateOrgIdentity } from "@app/hooks/api";
|
||||
import { useAddIdentityUniversalAuth } from "@app/hooks/api/identities";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -47,7 +45,7 @@ type Props = {
|
||||
handlePopUpToggle: (popUpName: keyof UsePopUpState<["identity"]>, state?: boolean) => void;
|
||||
};
|
||||
|
||||
export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
export const OrgIdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const navigate = useNavigate();
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
@@ -55,8 +53,8 @@ export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const { data: roles } = useGetOrgRoles(orgId);
|
||||
const isOrgIdentity = popUp?.identity?.data ? orgId === popUp?.identity?.data?.orgId : true;
|
||||
|
||||
const { mutateAsync: createMutateAsync } = useCreateIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentity();
|
||||
const { mutateAsync: createMutateAsync } = useCreateOrgIdentity();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateOrgIdentity();
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityUniversalAuth();
|
||||
|
||||
const {
|
||||
@@ -173,75 +171,66 @@ export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={popUp?.identity?.isOpen}
|
||||
onOpenChange={(isOpen) => {
|
||||
handlePopUpToggle("identity", isOpen);
|
||||
reset();
|
||||
}}
|
||||
>
|
||||
<ModalContent
|
||||
bodyClassName="overflow-visible"
|
||||
title={`${popUp?.identity?.data ? "Update" : "Create"} Identity`}
|
||||
>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
{isOrgIdentity && (
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="name"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="mb-4"
|
||||
label="Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Machine 1" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<form onSubmit={handleSubmit(onFormSubmit)}>
|
||||
{isOrgIdentity && (
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="name"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
className="mb-4"
|
||||
label="Name"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
>
|
||||
<Input {...field} placeholder="Machine 1" />
|
||||
</FormControl>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="role"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={`${popUp?.identity?.data ? "Update" : ""} Role`}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
/>
|
||||
)}
|
||||
<Controller
|
||||
control={control}
|
||||
name="role"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label={`${popUp?.identity?.data ? "Update" : ""} Role`}
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
>
|
||||
<FilterableSelect
|
||||
placeholder="Select role..."
|
||||
options={roles}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
getOptionValue={(option) => option.slug}
|
||||
getOptionLabel={(option) => option.name}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{isOrgIdentity && (
|
||||
<Controller
|
||||
control={control}
|
||||
name="hasDeleteProtection"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl errorText={error?.message} isError={Boolean(error)}>
|
||||
<Switch
|
||||
className="mr-2 ml-0 bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
containerClassName="flex-row-reverse w-fit"
|
||||
id="delete-protection-enabled"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={value}
|
||||
>
|
||||
<FilterableSelect
|
||||
placeholder="Select role..."
|
||||
options={roles}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
getOptionValue={(option) => option.slug}
|
||||
getOptionLabel={(option) => option.name}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{isOrgIdentity && (
|
||||
<Controller
|
||||
control={control}
|
||||
name="hasDeleteProtection"
|
||||
render={({ field: { onChange, value }, fieldState: { error } }) => (
|
||||
<FormControl errorText={error?.message} isError={Boolean(error)}>
|
||||
<Switch
|
||||
className="mr-2 ml-0 bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
containerClassName="flex-row-reverse w-fit"
|
||||
id="delete-protection-enabled"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={value}
|
||||
>
|
||||
<p>Delete Protection {value ? "Enabled" : "Disabled"}</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<p>Delete Protection {value ? "Enabled" : "Disabled"}</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isOrgIdentity && (
|
||||
<>
|
||||
<div>
|
||||
<FormLabel label="Metadata" />
|
||||
</div>
|
||||
@@ -303,26 +292,26 @@ export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
{popUp?.identity?.data ? "Update" : "Create"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpToggle("identity", false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
isLoading={isSubmitting}
|
||||
isDisabled={isSubmitting}
|
||||
>
|
||||
{popUp?.identity?.data ? "Update" : "Create"}
|
||||
</Button>
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
variant="plain"
|
||||
onClick={() => handlePopUpToggle("identity", false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -7,16 +7,21 @@ import { Link, useNavigate, useParams } from "@tanstack/react-router";
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { DeleteActionModal, PageHeader } from "@app/components/v2";
|
||||
import { Button, DeleteActionModal, Modal, ModalContent, PageHeader } from "@app/components/v2";
|
||||
import { ROUTE_PATHS } from "@app/const/routes";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import { useDeleteIdentity, useGetIdentityById } from "@app/hooks/api";
|
||||
import {
|
||||
OrgPermissionActions,
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
useOrganization
|
||||
} from "@app/context";
|
||||
import { useDeleteOrgIdentity, useGetOrgIdentityMembershipById } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
import { ViewIdentityAuthModal } from "@app/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/ViewIdentityAuthModal";
|
||||
import { OrgAccessControlTabSections } from "@app/types/org";
|
||||
|
||||
import { IdentityAuthMethodModal } from "../AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthMethodModal";
|
||||
import { IdentityModal } from "../AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityModal";
|
||||
import { OrgIdentityModal } from "../AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/OrgIdentityModal";
|
||||
import {
|
||||
IdentityAuthenticationSection,
|
||||
IdentityDetailsSection,
|
||||
@@ -31,8 +36,8 @@ const Page = () => {
|
||||
const identityId = params.identityId as string;
|
||||
const { currentOrg, isSubOrganization } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { mutateAsync: deleteIdentity } = useDeleteIdentity();
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
const { mutateAsync: deleteIdentity, isPending: isDeletingIdentity } = useDeleteOrgIdentity();
|
||||
const isAuthHidden = orgId !== data?.identity?.orgId;
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
@@ -46,7 +51,7 @@ const Page = () => {
|
||||
const onDeleteIdentitySubmit = async (id: string) => {
|
||||
await deleteIdentity({
|
||||
identityId: id,
|
||||
organizationId: orgId
|
||||
orgId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
@@ -81,7 +86,36 @@ const Page = () => {
|
||||
scope={isSubOrganization ? "namespace" : "org"}
|
||||
description={`${isSubOrganization ? "Sub-" : ""}Organization Identity`}
|
||||
title={data.identity.name}
|
||||
/>
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{isSubOrganization && data.identity.orgId !== currentOrg.id && (
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionActions.Delete}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
renderTooltip
|
||||
allowedLabel="Remove from sub-organization"
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="danger"
|
||||
variant="outline_bg"
|
||||
size="xs"
|
||||
isDisabled={!isAllowed}
|
||||
isLoading={isDeletingIdentity}
|
||||
onClick={() =>
|
||||
handlePopUpOpen("deleteIdentity", {
|
||||
identityId: data.identity.id,
|
||||
name: data.identity.name
|
||||
})
|
||||
}
|
||||
>
|
||||
Unlink Identity
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
)}
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div className="flex">
|
||||
<div className="mr-4 w-96">
|
||||
<IdentityDetailsSection
|
||||
@@ -100,7 +134,17 @@ const Page = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<Modal
|
||||
isOpen={popUp?.identity?.isOpen}
|
||||
onOpenChange={(isOpen) => handlePopUpToggle("identity", isOpen)}
|
||||
>
|
||||
<ModalContent
|
||||
bodyClassName="overflow-visible"
|
||||
title={`${popUp?.identity?.data ? "Update" : "Create"} Identity`}
|
||||
>
|
||||
<OrgIdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<IdentityAuthMethodModal
|
||||
popUp={popUp}
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
|
||||
@@ -4,7 +4,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { Button, Tooltip } from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import { IdentityAuthMethod, identityAuthToNameMap, useGetIdentityById } from "@app/hooks/api";
|
||||
import {
|
||||
IdentityAuthMethod,
|
||||
identityAuthToNameMap,
|
||||
useGetOrgIdentityMembershipById
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
@@ -16,7 +20,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IdentityAuthenticationSection = ({ identityId, handlePopUpOpen }: Props) => {
|
||||
const { data, refetch } = useGetIdentityById(identityId);
|
||||
const { data, refetch } = useGetOrgIdentityMembershipById(identityId);
|
||||
|
||||
return data ? (
|
||||
<div className="mt-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
|
||||
@@ -7,9 +7,9 @@ import { Button, IconButton, Tooltip } from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import { useTimedReset } from "@app/hooks";
|
||||
import {
|
||||
useGetIdentityById,
|
||||
useGetIdentityUniversalAuth,
|
||||
useGetIdentityUniversalAuthClientSecrets
|
||||
useGetIdentityUniversalAuthClientSecrets,
|
||||
useGetOrgIdentityMembershipById
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -30,7 +30,7 @@ export const IdentityClientSecrets = ({ identityId, handlePopUpOpen }: Props) =>
|
||||
initialState: "Copy Client ID to clipboard"
|
||||
});
|
||||
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
const { data: identityUniversalAuth } = useGetIdentityUniversalAuth(identityId);
|
||||
const { data: clientSecrets } = useGetIdentityUniversalAuthClientSecrets(identityId);
|
||||
return (
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
IconButton,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { useGetIdentityById, useGetIdentityTokensTokenAuth } from "@app/hooks/api";
|
||||
import { useGetIdentityTokensTokenAuth, useGetOrgIdentityMembershipById } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
@@ -23,7 +23,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IdentityTokens = ({ identityId, handlePopUpOpen }: Props) => {
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
const { data: tokens } = useGetIdentityTokensTokenAuth(identityId);
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects, useOrganization } from "@app/context";
|
||||
import { useTimedReset } from "@app/hooks";
|
||||
import { identityAuthToNameMap, useGetIdentityById } from "@app/hooks/api";
|
||||
import { identityAuthToNameMap, useGetOrgIdentityMembershipById } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
@@ -41,7 +41,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
|
||||
});
|
||||
const { isSubOrganization } = useOrganization();
|
||||
|
||||
const { data } = useGetIdentityById(identityId);
|
||||
const { data } = useGetOrgIdentityMembershipById(identityId);
|
||||
return data ? (
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||
@@ -86,7 +86,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
|
||||
}}
|
||||
disabled={!isAllowed}
|
||||
>
|
||||
Edit Identity
|
||||
{isOrgIdentity ? "Edit Identity" : "Edit Identity Role"}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
@@ -110,7 +110,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
|
||||
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||
disabled={!isAllowed}
|
||||
>
|
||||
Delete Identity
|
||||
{!isOrgIdentity ? "Remove From Sub-Organization" : "Delete Identity"}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import {
|
||||
useAddIdentityToWorkspace,
|
||||
useCreateProjectIdentityMembership,
|
||||
useGetIdentityProjectMemberships,
|
||||
useGetProjectRoles,
|
||||
useGetUserProjects,
|
||||
@@ -45,7 +45,7 @@ type Props = {
|
||||
const Content = ({ identityId, handlePopUpToggle }: Omit<Props, "popUp">) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { data: workspaces = [] } = useGetUserProjects();
|
||||
const { mutateAsync: addIdentityToWorkspace } = useAddIdentityToWorkspace();
|
||||
const { mutateAsync: addIdentityToWorkspace } = useCreateProjectIdentityMembership();
|
||||
|
||||
const {
|
||||
control,
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IconButton, Td, Tooltip, Tr } from "@app/components/v2";
|
||||
import { getProjectBaseURL } from "@app/helpers/project";
|
||||
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||
import { useGetUserProjects } from "@app/hooks/api";
|
||||
import { IdentityMembership } from "@app/hooks/api/identities/types";
|
||||
import { IdentityProjectMembershipV1 } from "@app/hooks/api/identities/types";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
export enum TabSections {
|
||||
@@ -20,7 +20,7 @@ export enum TabSections {
|
||||
}
|
||||
|
||||
type Props = {
|
||||
membership: IdentityMembership;
|
||||
membership: IdentityProjectMembershipV1;
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["removeIdentityFromProject"]>,
|
||||
data?: object
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { DeleteActionModal, IconButton } from "@app/components/v2";
|
||||
import { useDeleteIdentityFromWorkspace } from "@app/hooks/api";
|
||||
import { useDeleteProjectIdentityMembership } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { IdentityAddToProjectModal } from "./IdentityAddToProjectModal";
|
||||
@@ -14,7 +14,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const IdentityProjectsSection = ({ identityId }: Props) => {
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteIdentityFromWorkspace();
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteProjectIdentityMembership();
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"addIdentityToProject",
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { UseMutationResult } from "@tanstack/react-query";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import ms from "ms";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import { Button } from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
|
||||
import { IdentityAuthFieldDisplay } from "./IdentityAuthFieldDisplay";
|
||||
|
||||
@@ -31,7 +38,11 @@ export const LockoutFields = ({
|
||||
|
||||
const [lockedOutState, setLockedOutState] = useState(lockedOut);
|
||||
|
||||
const clearLockouts = async () => {
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
async function clearLockouts() {
|
||||
const deleted = await mutateAsync({ identityId });
|
||||
createNotification({
|
||||
text: `Successfully cleared ${deleted} lockout${deleted === 1 ? "" : "s"}`,
|
||||
@@ -39,13 +50,23 @@ export const LockoutFields = ({
|
||||
});
|
||||
setLockedOutState(false);
|
||||
onResetAllLockouts();
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="col-span-2 mt-3 flex justify-between border-b border-mineshaft-500 pb-2">
|
||||
<span className="text-bunker-300">Lockout Options</span>
|
||||
<OrgPermissionCan I={OrgPermissionIdentityActions.Edit} a={OrgPermissionSubjects.Identity}>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={projectId ? ProjectPermissionIdentityActions.Edit : OrgPermissionIdentityActions.Edit}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isDisabled={!isAllowed || !lockedOutState || isPending}
|
||||
@@ -57,7 +78,7 @@ export const LockoutFields = ({
|
||||
Reset All Lockouts
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</div>
|
||||
<IdentityAuthFieldDisplay label="Lockout Threshold">
|
||||
{data.lockoutThreshold}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faBan, faEdit, faKey, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
@@ -20,7 +22,12 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useRevokeIdentityTokenAuthToken } from "@app/hooks/api";
|
||||
import { IdentityAccessToken } from "@app/hooks/api/identities/types";
|
||||
@@ -37,6 +44,10 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
"revokeToken"
|
||||
] as const);
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(5);
|
||||
|
||||
@@ -68,7 +79,17 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
<div className="col-span-2 mt-3">
|
||||
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
|
||||
<span className="text-bunker-300">Access Tokens</span>
|
||||
<OrgPermissionCan I={OrgPermissionIdentityActions.Edit} a={OrgPermissionSubjects.Identity}>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={projectId ? ProjectPermissionIdentityActions.Edit : OrgPermissionIdentityActions.Edit}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
size="xs"
|
||||
@@ -84,7 +105,7 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
Add Token
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</div>
|
||||
<TableContainer className="mt-4 rounded-none border-none">
|
||||
<Table>
|
||||
@@ -132,9 +153,20 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
</Td>
|
||||
<Td>
|
||||
<div className="flex items-center gap-2">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Tooltip content={isAllowed ? "Edit Token" : "Access Restricted"}>
|
||||
@@ -155,11 +187,22 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
{!isAccessTokenRevoked && (
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Tooltip content={isAllowed ? "Revoke Token" : "Access Restricted"}>
|
||||
@@ -181,7 +224,7 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faKey, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
@@ -20,7 +22,12 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
import { usePopUp } from "@app/hooks";
|
||||
import { useRevokeIdentityUniversalAuthClientSecret } from "@app/hooks/api";
|
||||
import { ClientSecretData } from "@app/hooks/api/identities/types";
|
||||
@@ -37,6 +44,10 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
"clientSecret"
|
||||
] as const);
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [perPage, setPerPage] = useState(5);
|
||||
|
||||
@@ -60,7 +71,17 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
<div className="col-span-2">
|
||||
<div className="flex items-end justify-between border-b border-mineshaft-500 pb-2">
|
||||
<span className="text-bunker-300">Client Secrets</span>
|
||||
<OrgPermissionCan I={OrgPermissionIdentityActions.Edit} a={OrgPermissionSubjects.Identity}>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={projectId ? ProjectPermissionIdentityActions.Edit : OrgPermissionIdentityActions.Edit}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isDisabled={!isAllowed}
|
||||
@@ -76,7 +97,7 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
Add Client Secret
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</div>
|
||||
<TableContainer className="mt-4 rounded-none border-none">
|
||||
<Table>
|
||||
@@ -120,9 +141,20 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
{expiresAt ? format(expiresAt, "yyyy-MM-dd") : "-"}
|
||||
</Td>
|
||||
<Td>
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Tooltip content={isAllowed ? "Delete Secret" : "Access Restricted"}>
|
||||
@@ -143,7 +175,7 @@ export const IdentityUniversalAuthClientSecretsTable = ({ clientSecrets, identit
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
|
||||
@@ -49,6 +49,7 @@ export const ViewIdentityAliCloudAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
|
||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { DeleteActionModal, Modal, ModalContent } from "@app/components/v2";
|
||||
@@ -46,8 +48,7 @@ type Props = {
|
||||
|
||||
type TRevokeOptions = {
|
||||
identityId: string;
|
||||
organizationId: string;
|
||||
};
|
||||
} & ({ projectId: string } | { organizationId: string });
|
||||
|
||||
export const Content = ({
|
||||
identityId,
|
||||
@@ -61,7 +62,9 @@ export const Content = ({
|
||||
>) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const orgId = currentOrg?.id || "";
|
||||
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
|
||||
"revokeAuthMethod",
|
||||
"upgradePlan",
|
||||
@@ -142,7 +145,11 @@ export const Content = ({
|
||||
const handleDeleteAuthMethod = async () => {
|
||||
await revokeMethod({
|
||||
identityId,
|
||||
organizationId: orgId
|
||||
...(projectId
|
||||
? { projectId }
|
||||
: {
|
||||
organizationId: orgId
|
||||
})
|
||||
});
|
||||
|
||||
createNotification({
|
||||
|
||||
@@ -46,6 +46,7 @@ export const ViewIdentityAwsAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -46,6 +46,7 @@ export const ViewIdentityAzureAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { ReactNode } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import { faChevronDown, faEdit, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useParams } from "@tanstack/react-router";
|
||||
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { VariablePermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
@@ -10,15 +12,25 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger
|
||||
} from "@app/components/v2";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/context";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionSubjects,
|
||||
ProjectPermissionIdentityActions,
|
||||
ProjectPermissionSub
|
||||
} from "@app/context";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
onEdit: VoidFunction;
|
||||
onDelete: VoidFunction;
|
||||
identityId: string;
|
||||
};
|
||||
|
||||
export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props) => {
|
||||
export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit, identityId }: Props) => {
|
||||
const { projectId } = useParams({
|
||||
strict: false
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
@@ -36,9 +48,20 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="mt-3 min-w-[120px]" align="end">
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Edit}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Edit
|
||||
: OrgPermissionIdentityActions.Edit
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
@@ -49,10 +72,21 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
<OrgPermissionCan
|
||||
I={OrgPermissionIdentityActions.Delete}
|
||||
a={OrgPermissionSubjects.Identity}
|
||||
</VariablePermissionCan>
|
||||
<VariablePermissionCan
|
||||
type={projectId ? "project" : "org"}
|
||||
I={
|
||||
projectId
|
||||
? ProjectPermissionIdentityActions.Delete
|
||||
: OrgPermissionIdentityActions.Delete
|
||||
}
|
||||
a={
|
||||
projectId
|
||||
? subject(ProjectPermissionSub.Identity, {
|
||||
identityId
|
||||
})
|
||||
: OrgPermissionSubjects.Identity
|
||||
}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
@@ -63,7 +97,7 @@ export const ViewIdentityContentWrapper = ({ children, onDelete, onEdit }: Props
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</VariablePermissionCan>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
@@ -46,6 +46,7 @@ export const ViewIdentityGcpAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -49,6 +49,7 @@ export const ViewIdentityJwtAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -59,6 +59,7 @@ export const ViewIdentityKubernetesAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -52,6 +52,7 @@ export const ViewIdentityLdapAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -46,6 +46,7 @@ export const ViewIdentityOciAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -48,6 +48,7 @@ export const ViewIdentityOidcAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -51,6 +51,7 @@ export const ViewIdentityTlsCertAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -49,6 +49,7 @@ export const ViewIdentityTokenAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
<IdentityAuthFieldDisplay label="Access Token TTL (seconds)">
|
||||
{data.accessTokenTTL}
|
||||
|
||||
@@ -66,6 +66,7 @@ export const ViewIdentityUniversalAuthContent = ({
|
||||
<ViewIdentityContentWrapper
|
||||
onEdit={() => handlePopUpOpen("identityAuthMethod")}
|
||||
onDelete={onDelete}
|
||||
identityId={identityId}
|
||||
>
|
||||
{Number(data.accessTokenPeriod) > 0 ? (
|
||||
<IdentityAuthFieldDisplay label="Access Token Period (seconds)">
|
||||
|
||||
@@ -26,10 +26,21 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
||||
return [
|
||||
...resourceOptions,
|
||||
// We are temporarily showing these resources so that we can gauge interest before committing
|
||||
{ name: "OracleDB", resource: PamResourceType.OracleDB },
|
||||
{ name: "SQLite", resource: PamResourceType.SQLite },
|
||||
{ name: "Microsoft SQL Server", resource: PamResourceType.MsSQL },
|
||||
{ name: "MongoDB", resource: PamResourceType.MongoDB },
|
||||
{ name: "Cassandra", resource: PamResourceType.Cassandra },
|
||||
{ name: "CockroachDB", resource: PamResourceType.CockroachDB },
|
||||
{ name: "DynamoDB", resource: PamResourceType.DynamoDB },
|
||||
{ name: "Snowflake", resource: PamResourceType.Snowflake },
|
||||
{ name: "Elasticsearch", resource: PamResourceType.Elasticsearch },
|
||||
{ name: "Redis", resource: PamResourceType.Redis },
|
||||
{ name: "RDP", resource: PamResourceType.RDP },
|
||||
{ name: "SSH", resource: PamResourceType.SSH },
|
||||
{ name: "Kubernetes", resource: PamResourceType.Kubernetes },
|
||||
{ name: "MCP", resource: PamResourceType.MCP }
|
||||
{ name: "MCP", resource: PamResourceType.MCP },
|
||||
{ name: "Web Application", resource: PamResourceType.WebApp }
|
||||
];
|
||||
}, [resourceOptions]);
|
||||
|
||||
@@ -39,11 +50,13 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
||||
|
||||
const filteredOptions = useMemo(
|
||||
() =>
|
||||
appendedResourceOptions?.filter(
|
||||
({ name, resource }) =>
|
||||
name.toLowerCase().includes(search.trim().toLowerCase()) ||
|
||||
resource.toLowerCase().includes(search.trim().toLowerCase())
|
||||
) ?? [],
|
||||
appendedResourceOptions
|
||||
?.filter(
|
||||
({ name, resource }) =>
|
||||
name.toLowerCase().includes(search.trim().toLowerCase()) ||
|
||||
resource.toLowerCase().includes(search.trim().toLowerCase())
|
||||
)
|
||||
.sort((a, b) => a.name.localeCompare(b.name)) ?? [],
|
||||
[appendedResourceOptions, search]
|
||||
);
|
||||
|
||||
@@ -67,7 +80,15 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
||||
resource === PamResourceType.RDP ||
|
||||
resource === PamResourceType.SSH ||
|
||||
resource === PamResourceType.Kubernetes ||
|
||||
resource === PamResourceType.MCP
|
||||
resource === PamResourceType.MCP ||
|
||||
resource === PamResourceType.Redis ||
|
||||
resource === PamResourceType.MongoDB ||
|
||||
resource === PamResourceType.WebApp ||
|
||||
resource === PamResourceType.Cassandra ||
|
||||
resource === PamResourceType.CockroachDB ||
|
||||
resource === PamResourceType.Elasticsearch ||
|
||||
resource === PamResourceType.Snowflake ||
|
||||
resource === PamResourceType.DynamoDB
|
||||
) {
|
||||
handlePopUpOpen("upgradePlan", {
|
||||
text: "Your current plan does not include access to this resource type. To unlock this feature, please upgrade to Infisical Enterprise plan.",
|
||||
@@ -107,17 +128,16 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
||||
onClick={() => handleResourceSelect(option.resource)}
|
||||
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
|
||||
>
|
||||
<div className="relative">
|
||||
<div className="relative my-auto">
|
||||
<img
|
||||
src={`/images/integrations/${image}`}
|
||||
style={{
|
||||
width: `${size}px`
|
||||
}}
|
||||
className="mt-auto"
|
||||
alt={`${name} logo`}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-auto max-w-xs text-center text-xs font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
||||
<div className="max-w-xs text-center text-xs font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
||||
{name}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { subject } from "@casl/ability";
|
||||
import {
|
||||
faArrowDown,
|
||||
@@ -11,7 +12,8 @@ import {
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { format } from "date-fns";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { LinkIcon, PlusIcon } from "lucide-react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
@@ -29,6 +31,8 @@ import {
|
||||
HoverCardTrigger,
|
||||
IconButton,
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Pagination,
|
||||
Spinner,
|
||||
Table,
|
||||
@@ -42,8 +46,20 @@ import {
|
||||
Tooltip,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { DocumentationLinkBadge } from "@app/components/v3";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context";
|
||||
import { Blur } from "@app/components/v2/Blur";
|
||||
import {
|
||||
Badge,
|
||||
DocumentationLinkBadge,
|
||||
OrgIcon,
|
||||
ProjectIcon,
|
||||
SubOrgIcon
|
||||
} from "@app/components/v3";
|
||||
import {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
useOrganization,
|
||||
useProject
|
||||
} from "@app/context";
|
||||
import { getProjectBaseURL } from "@app/helpers/project";
|
||||
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||
import {
|
||||
@@ -53,19 +69,33 @@ import {
|
||||
} from "@app/helpers/userTablePreferences";
|
||||
import { withProjectPermission } from "@app/hoc";
|
||||
import { usePagination, useResetPageHelper } from "@app/hooks";
|
||||
import { useDeleteIdentityFromWorkspace, useGetWorkspaceIdentityMemberships } from "@app/hooks/api";
|
||||
import {
|
||||
useDeleteProjectIdentity,
|
||||
useDeleteProjectIdentityMembership,
|
||||
useListProjectIdentityMemberships
|
||||
} from "@app/hooks/api";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { ProjectIdentityOrderBy } from "@app/hooks/api/projects/types";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
import { ProjectIdentityModal } from "@app/pages/project/AccessControlPage/components/IdentityTab/components/ProjectIdentityModal";
|
||||
|
||||
import { IdentityModal } from "./components/IdentityModal";
|
||||
import { ProjectLinkIdentityModal } from "./components/ProjectLinkIdentityModal";
|
||||
|
||||
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
|
||||
|
||||
enum WizardSteps {
|
||||
SelectAction = "select-action",
|
||||
LinkIdentity = "link-identity",
|
||||
ProjectIdentity = "project-identity"
|
||||
}
|
||||
|
||||
export const IdentityTab = withProjectPermission(
|
||||
() => {
|
||||
const { currentProject, projectId } = useProject();
|
||||
const navigate = useNavigate();
|
||||
const { isSubOrganization, currentOrg } = useOrganization();
|
||||
|
||||
const [wizardStep, setWizardStep] = useState(WizardSteps.SelectAction);
|
||||
|
||||
const {
|
||||
offset,
|
||||
@@ -90,7 +120,7 @@ export const IdentityTab = withProjectPermission(
|
||||
setUserTablePreference("projectIdentityTable", PreferenceKey.PerPage, newPerPage);
|
||||
};
|
||||
|
||||
const { data, isPending, isFetching } = useGetWorkspaceIdentityMemberships(
|
||||
const { data, isPending, isFetching } = useListProjectIdentityMemberships(
|
||||
{
|
||||
projectId,
|
||||
offset,
|
||||
@@ -110,28 +140,41 @@ export const IdentityTab = withProjectPermission(
|
||||
setPage
|
||||
});
|
||||
|
||||
const { mutateAsync: deleteMutateAsync } = useDeleteIdentityFromWorkspace();
|
||||
const { mutateAsync: deleteMembershipMutateAsync } = useDeleteProjectIdentityMembership();
|
||||
const { mutateAsync: deleteProjectIdentity } = useDeleteProjectIdentity();
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"identity",
|
||||
"createIdentity",
|
||||
"deleteIdentity",
|
||||
"upgradePlan"
|
||||
"upgradePlan",
|
||||
"addOptions"
|
||||
] as const);
|
||||
|
||||
const onRemoveIdentitySubmit = async (identityId: string) => {
|
||||
await deleteMutateAsync({
|
||||
identityId,
|
||||
projectId
|
||||
});
|
||||
const onRemoveIdentitySubmit = async (identityId: string, isProjectIdentity: boolean) => {
|
||||
if (isProjectIdentity) {
|
||||
await deleteProjectIdentity({
|
||||
identityId,
|
||||
projectId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully removed identity from project",
|
||||
type: "success"
|
||||
});
|
||||
createNotification({
|
||||
text: "Successfully deleted project identity",
|
||||
type: "success"
|
||||
});
|
||||
} else {
|
||||
await deleteMembershipMutateAsync({
|
||||
identityId,
|
||||
projectId
|
||||
});
|
||||
|
||||
createNotification({
|
||||
text: "Successfully removed identity from project",
|
||||
type: "success"
|
||||
});
|
||||
}
|
||||
|
||||
handlePopUpClose("deleteIdentity");
|
||||
};
|
||||
|
||||
const handleSort = (column: ProjectIdentityOrderBy) => {
|
||||
if (column === orderBy) {
|
||||
setOrderDirection((prev) =>
|
||||
@@ -144,6 +187,12 @@ export const IdentityTab = withProjectPermission(
|
||||
setOrderDirection(OrderByDirection.ASC);
|
||||
};
|
||||
|
||||
const noAccessIdentityCount = Math.max(
|
||||
(page * perPage > totalCount ? totalCount % perPage : perPage) -
|
||||
(data?.identityMemberships?.length || 0),
|
||||
0
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
@@ -151,22 +200,23 @@ export const IdentityTab = withProjectPermission(
|
||||
<p className="text-xl font-medium text-mineshaft-100">Identities</p>
|
||||
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
|
||||
</div>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="secondary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("identity")}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Add Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<div className="flex items-center">
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.Identity}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
variant="outline_bg"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("createIdentity")}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Create Identity
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
containerClassName="mb-4"
|
||||
@@ -202,7 +252,7 @@ export const IdentityTab = withProjectPermission(
|
||||
</div>
|
||||
</Th>
|
||||
<Th className="w-1/3">Role</Th>
|
||||
<Th>Added on</Th>
|
||||
<Th>Managed by</Th>
|
||||
<Th className="w-5">{isFetching ? <Spinner size="xs" /> : null}</Th>
|
||||
</Tr>
|
||||
</THead>
|
||||
@@ -213,9 +263,8 @@ export const IdentityTab = withProjectPermission(
|
||||
data.identityMemberships.length > 0 &&
|
||||
data.identityMemberships.map((identityMember) => {
|
||||
const {
|
||||
identity: { id, name },
|
||||
roles,
|
||||
createdAt
|
||||
identity: { id, name, projectId: identityProjectId, orgId: identityOrgId },
|
||||
roles
|
||||
} = identityMember;
|
||||
return (
|
||||
<Tr
|
||||
@@ -339,7 +388,36 @@ export const IdentityTab = withProjectPermission(
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
||||
<Td>
|
||||
<Badge
|
||||
variant={
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
identityProjectId
|
||||
? "project"
|
||||
: isSubOrganization && currentOrg.id === identityOrgId
|
||||
? "sub-org"
|
||||
: "org"
|
||||
}
|
||||
>
|
||||
{/* eslint-disable-next-line no-nested-ternary */}
|
||||
{identityProjectId ? (
|
||||
<>
|
||||
<ProjectIcon />
|
||||
Project
|
||||
</>
|
||||
) : isSubOrganization && currentOrg.id === identityOrgId ? (
|
||||
<>
|
||||
<SubOrgIcon />
|
||||
Sub-Organization
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<OrgIcon />
|
||||
Organization
|
||||
</>
|
||||
)}
|
||||
</Badge>
|
||||
</Td>
|
||||
<Td className="flex justify-end space-x-2">
|
||||
<Tooltip className="max-w-sm text-center" content="Options">
|
||||
<DropdownMenu>
|
||||
@@ -369,11 +447,12 @@ export const IdentityTab = withProjectPermission(
|
||||
evt.preventDefault();
|
||||
handlePopUpOpen("deleteIdentity", {
|
||||
identityId: id,
|
||||
name
|
||||
name,
|
||||
isProjectIdentity: Boolean(identityProjectId)
|
||||
});
|
||||
}}
|
||||
>
|
||||
Remove Identity From Project
|
||||
{identityProjectId ? "Delete Identity" : "Remove From Project"}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
@@ -384,6 +463,20 @@ export const IdentityTab = withProjectPermission(
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
{!isPending &&
|
||||
data &&
|
||||
data?.totalCount !== 0 &&
|
||||
Array.from(Array(noAccessIdentityCount)).map((_e, i) => (
|
||||
<Tr key={`hid-identity-${i + 1}`}>
|
||||
<Td>No Access</Td>
|
||||
<Td colSpan={3}>
|
||||
<Blur
|
||||
className="w-min"
|
||||
tooltipText="You do not have permission to read this identity."
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</TBody>
|
||||
</Table>
|
||||
{!isPending && data && totalCount > 0 && (
|
||||
@@ -395,18 +488,113 @@ export const IdentityTab = withProjectPermission(
|
||||
onChangePerPage={handlePerPageChange}
|
||||
/>
|
||||
)}
|
||||
{!isPending && data && data?.identityMemberships.length === 0 && (
|
||||
<EmptyState
|
||||
title={
|
||||
debouncedSearch.trim().length > 0
|
||||
? "No identities match search filter"
|
||||
: "No identities have been added to this project"
|
||||
}
|
||||
icon={faServer}
|
||||
/>
|
||||
)}
|
||||
{!isPending &&
|
||||
data &&
|
||||
data?.identityMemberships.length === 0 &&
|
||||
data?.totalCount === 0 && (
|
||||
<EmptyState
|
||||
title={
|
||||
debouncedSearch.trim().length > 0
|
||||
? "No identities match search filter"
|
||||
: "No identities have been added to this project"
|
||||
}
|
||||
icon={faServer}
|
||||
/>
|
||||
)}
|
||||
</TableContainer>
|
||||
<IdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
<Modal
|
||||
isOpen={popUp.createIdentity.isOpen}
|
||||
onOpenChange={(open) => {
|
||||
handlePopUpToggle("createIdentity", open);
|
||||
if (!open) setWizardStep(WizardSteps.SelectAction);
|
||||
}}
|
||||
>
|
||||
<ModalContent
|
||||
bodyClassName="overflow-visible"
|
||||
title="Add Project Identity"
|
||||
subTitle="Create a new identity or assign an existing identity"
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
{wizardStep === WizardSteps.SelectAction && (
|
||||
<motion.div
|
||||
key="select-type-step"
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: -30 }}
|
||||
>
|
||||
<div
|
||||
className="cursor-pointer rounded-md border border-mineshaft-600 p-4 transition-all hover:bg-mineshaft-700"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setWizardStep(WizardSteps.ProjectIdentity)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
setWizardStep(WizardSteps.ProjectIdentity);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<PlusIcon size="1rem" />
|
||||
<div>Create New Identity</div>
|
||||
</div>
|
||||
<div className="mt-2 text-xs text-mineshaft-300">
|
||||
Create a new machine identity specifically for this project. This identity
|
||||
will be managed at the project-level.
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="mt-4 cursor-pointer rounded-md border border-mineshaft-600 p-4 transition-all hover:bg-mineshaft-700"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setWizardStep(WizardSteps.LinkIdentity)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
setWizardStep(WizardSteps.LinkIdentity);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<LinkIcon size="1rem" />
|
||||
<div>Assign Existing Identity</div>
|
||||
</div>
|
||||
<div className="mt-2 text-xs text-mineshaft-300">
|
||||
Assign an existing identity from your organization. The identity will continue
|
||||
to be managed at its original scope.
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
{wizardStep === WizardSteps.ProjectIdentity && (
|
||||
<motion.div
|
||||
key="identity-step"
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: -30 }}
|
||||
>
|
||||
<ProjectIdentityModal
|
||||
onClose={() => {
|
||||
handlePopUpClose("createIdentity");
|
||||
setWizardStep(WizardSteps.SelectAction);
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
{wizardStep === WizardSteps.LinkIdentity && (
|
||||
<motion.div
|
||||
key="link-step"
|
||||
transition={{ duration: 0.1 }}
|
||||
initial={{ opacity: 0, translateX: 30 }}
|
||||
animate={{ opacity: 1, translateX: 0 }}
|
||||
exit={{ opacity: 0, translateX: -30 }}
|
||||
>
|
||||
<ProjectLinkIdentityModal handlePopUpToggle={handlePopUpToggle} />
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.deleteIdentity.isOpen}
|
||||
title={`Are you sure you want to remove ${
|
||||
@@ -416,7 +604,8 @@ export const IdentityTab = withProjectPermission(
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={() =>
|
||||
onRemoveIdentitySubmit(
|
||||
(popUp?.deleteIdentity?.data as { identityId: string })?.identityId
|
||||
popUp?.deleteIdentity?.data?.identityId,
|
||||
popUp?.deleteIdentity?.data?.isProjectIdentity
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||