mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 20:28:16 +00:00
Merge remote-tracking branch 'origin/main' into feat/ENG-3443
This commit is contained in:
+7
-7
@@ -8,15 +8,15 @@
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="
|
||||
default-src 'self';
|
||||
connect-src 'self' https://*.posthog.com http://127.0.0.1:* https://cdn.jsdelivr.net/npm/@lottiefiles/[email protected]/dist/dotlottie-player.wasm;
|
||||
script-src 'self' https://*.posthog.com https://js.stripe.com https://api.stripe.com https://widget.intercom.io https://js.intercomcdn.com https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net/npm/@lottiefiles/[email protected]/dist/dotlottie-player.wasm;
|
||||
style-src 'self' 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com;
|
||||
connect-src 'self' https://d1zwf0dwl0k2ky.cloudfront.net https://*.posthog.com http://127.0.0.1:* https://cdn.jsdelivr.net/npm/@lottiefiles/[email protected]/dist/dotlottie-player.wasm;
|
||||
script-src 'self' https://d1zwf0dwl0k2ky.cloudfront.net https://*.posthog.com https://js.stripe.com https://api.stripe.com https://widget.intercom.io https://js.intercomcdn.com https://hcaptcha.com https://*.hcaptcha.com 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net/npm/@lottiefiles/[email protected]/dist/dotlottie-player.wasm;
|
||||
style-src 'self' https://d1zwf0dwl0k2ky.cloudfront.net 'unsafe-inline' https://hcaptcha.com https://*.hcaptcha.com;
|
||||
child-src https://api.stripe.com;
|
||||
frame-src https://js.stripe.com/ https://api.stripe.com https://www.youtube.com/ https://hcaptcha.com https://*.hcaptcha.com;
|
||||
connect-src 'self' wss://nexus-websocket-a.intercom.io https://api-iam.intercom.io https://api.heroku.com/ https://id.heroku.com/oauth/authorize https://id.heroku.com/oauth/token https://checkout.stripe.com https://app.posthog.com https://api.stripe.com https://api.pwnedpasswords.com http://127.0.0.1:* https://hcaptcha.com https://*.hcaptcha.com;
|
||||
img-src 'self' https://static.intercomassets.com https://js.intercomcdn.com https://downloads.intercomcdn.com https://*.stripe.com https://i.ytimg.com/ data:;
|
||||
media-src https://js.intercomcdn.com;
|
||||
font-src 'self' https://fonts.intercomcdn.com/ https://fonts.gstatic.com;
|
||||
connect-src 'self' https://d1zwf0dwl0k2ky.cloudfront.net wss://nexus-websocket-a.intercom.io https://api-iam.intercom.io https://api.heroku.com/ https://id.heroku.com/oauth/authorize https://id.heroku.com/oauth/token https://checkout.stripe.com https://app.posthog.com https://api.stripe.com https://api.pwnedpasswords.com http://127.0.0.1:* https://hcaptcha.com https://*.hcaptcha.com;
|
||||
img-src 'self' https://d1zwf0dwl0k2ky.cloudfront.net https://static.intercomassets.com https://js.intercomcdn.com https://downloads.intercomcdn.com https://*.stripe.com https://i.ytimg.com/ data:;
|
||||
media-src https://d1zwf0dwl0k2ky.cloudfront.net https://js.intercomcdn.com;
|
||||
font-src 'self' https://d1zwf0dwl0k2ky.cloudfront.net https://fonts.intercomcdn.com/ https://fonts.gstatic.com;
|
||||
"
|
||||
/>
|
||||
<title>Infisical</title>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 120 60" width="120" height="60" style="enable-background:new 0 0 120 60;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#808285;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:#005B99;}
|
||||
.st3{enable-background:new ;}
|
||||
.st4{fill:#77787B;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M34.1,42.6h9.4v-3.2C41.5,41.2,38.2,42.3,34.1,42.6L34.1,42.6z"/>
|
||||
<path class="st0" d="M17.3,40.1v2.5h11.9c-2.4-0.2-5-0.6-7.6-1.2C20.1,41,18.7,40.6,17.3,40.1L17.3,40.1z"/>
|
||||
|
||||
<radialGradient id="SVGID_1_" cx="-183.5882" cy="811.1324" r="47.498" gradientTransform="matrix(1 0 0 1 241.0864 -776.3726)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" style="stop-color:#0095DA"/>
|
||||
<stop offset="0.21" style="stop-color:#0095DA"/>
|
||||
<stop offset="0.33" style="stop-color:#00ACE4"/>
|
||||
<stop offset="0.9045" style="stop-color:#005093"/>
|
||||
<stop offset="0.9335" style="stop-color:#005396"/>
|
||||
<stop offset="0.954" style="stop-color:#005C9F"/>
|
||||
<stop offset="0.9718" style="stop-color:#006BAE"/>
|
||||
<stop offset="0.988" style="stop-color:#0080C4"/>
|
||||
<stop offset="1" style="stop-color:#0095DA"/>
|
||||
</radialGradient>
|
||||
<path class="st1" d="M43.5,18.5H29.2C23,17.1,15.4,17.1,10,18.2c2.4-0.3,5.1-0.3,7.8,0.1c0.7,0.1,1.3,0.2,2,0.3l0,0
|
||||
c2.9,0.5,5.7,1.2,8.1,2.2l0,0c0.3,0.1,0.5,0.2,0.8,0.3h0c0.1,0,0.2,0.1,0.3,0.1h0c0.1,0,0.2,0.1,0.3,0.1h0c0.1,0,0.2,0.1,0.2,0.1
|
||||
l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.2,0.1,0.2,0.1l0,0l0,0h0c0.1,0,0.1,0.1,0.2,0.1l0,0
|
||||
c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1
|
||||
l0.1,0c0.1,0,0.1,0.1,0.2,0.1l0.1,0c0.1,0,0.1,0.1,0.2,0.1l0.1,0c0.1,0,0.1,0.1,0.2,0.1l0.1,0c0.1,0,0.1,0.1,0.1,0.1l0.1,0.1
|
||||
c0.1,0,0.1,0.1,0.1,0.1l0.1,0.1c0.1,0,0.1,0.1,0.1,0.1l0.1,0.1c0,0,0.1,0.1,0.1,0.1c3.2,2.2,5.1,4.9,5.1,7.6c0,3.1-2.6,5.7-6.8,7.2
|
||||
c2.9-1.5,4.6-3.6,4.6-6.1c0-3.1-2.7-6.3-7-8.7c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1
|
||||
c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1l-0.2-0.1c-0.1,0-0.2-0.1-0.2-0.1
|
||||
l-0.1-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1
|
||||
L26,22c-0.1,0-0.2-0.1-0.3-0.1h0l-0.2-0.1l0,0c-0.1,0-0.2-0.1-0.3-0.1l-0.1,0c-0.1-0.1-0.2-0.1-0.4-0.1h0c-0.1,0-0.2-0.1-0.3-0.1h0
|
||||
c-0.1-0.1-0.3-0.1-0.5-0.2l-0.1,0c-0.1-0.1-0.3-0.1-0.5-0.1h0c-0.3-0.1-0.5-0.2-0.8-0.3l0,0c-0.3-0.1-0.6-0.2-0.8-0.3l0,0
|
||||
c-0.2-0.1-0.3-0.1-0.5-0.1l0,0c-0.7-0.2-1.5-0.4-2.3-0.5l0,0c-0.6-0.1-1.2-0.2-1.8-0.3v19.2c0.2,0.1,0.4,0.1,0.6,0.1
|
||||
C30.3,42,41,39.4,41.8,33.2c0.4-3.3-2-6.9-6.1-10c3.3,1.9,6,4.1,7.8,6.4c1,1.4,1.7,2.7,2,4.1c-0.1-1.9-0.9-4.8-2-6.9L43.5,18.5
|
||||
L43.5,18.5z"/>
|
||||
<g>
|
||||
<path class="st2" d="M67.5,26.9c0,1-0.2,2-0.7,2.9c-0.4,0.9-1,1.7-1.8,2.3c-0.8,0.7-1.7,1.2-2.8,1.6c-1.1,0.4-2.2,0.6-3.5,0.6H49
|
||||
v-9h4.5v5.3h5.2c0.6,0,1.2-0.1,1.7-0.3c0.5-0.2,1-0.4,1.4-0.7c0.4-0.3,0.7-0.7,0.9-1.1c0.2-0.4,0.3-0.9,0.3-1.4
|
||||
c0-0.5-0.1-1-0.3-1.4c-0.2-0.4-0.5-0.8-0.9-1.1c-0.4-0.3-0.8-0.6-1.4-0.7c-0.5-0.2-1.1-0.3-1.7-0.3H49l2.9-3.8h6.8
|
||||
c1.3,0,2.4,0.2,3.5,0.5c1.1,0.3,2,0.8,2.8,1.5s1.4,1.4,1.8,2.3C67.2,24.9,67.5,25.8,67.5,26.9z"/>
|
||||
<g>
|
||||
<path class="st2" d="M82.8,21.4v6.8l-8.9-8c-0.4-0.3-0.7-0.5-1-0.6c-0.3-0.1-0.6-0.1-0.8-0.1c-0.3,0-0.6,0.1-0.9,0.1
|
||||
c-0.3,0.1-0.6,0.3-0.8,0.5c-0.2,0.2-0.4,0.5-0.5,0.8c-0.1,0.3-0.2,0.8-0.2,1.2v12h4.1v-8.5l8.9,8c0.3,0.3,0.7,0.5,0.9,0.6
|
||||
c0.3,0.1,0.6,0.1,0.8,0.1c0.3,0,0.6-0.1,0.9-0.1c0.3-0.1,0.6-0.3,0.8-0.5c0.2-0.2,0.4-0.5,0.5-0.8c0.1-0.3,0.2-0.8,0.2-1.2V19.9
|
||||
L82.8,21.4z"/>
|
||||
</g>
|
||||
<path class="st2" d="M103,25.5c1.8,0,3.1,0.3,4,1c0.9,0.7,1.4,1.6,1.4,3c0,0.7-0.1,1.4-0.3,2c-0.2,0.6-0.6,1.1-1.1,1.5
|
||||
c-0.5,0.4-1.2,0.7-1.9,0.9c-0.8,0.2-1.7,0.3-2.8,0.3H88.7l2.9-3.7h11c0.5,0,0.9-0.1,1.2-0.3c0.3-0.2,0.4-0.4,0.4-0.8
|
||||
s-0.1-0.7-0.4-0.8c-0.3-0.2-0.6-0.2-1.2-0.2h-7.9c-0.9,0-1.8-0.1-2.4-0.3c-0.7-0.2-1.2-0.5-1.7-0.8c-0.5-0.4-0.8-0.8-1-1.3
|
||||
c-0.2-0.5-0.3-1.1-0.3-1.7c0-0.7,0.1-1.3,0.4-1.9c0.2-0.6,0.6-1,1.1-1.4c0.5-0.4,1.1-0.7,1.9-0.9c0.8-0.2,1.7-0.3,2.8-0.3h12.6
|
||||
l-2.9,3.8H95.1c-0.5,0-0.9,0.1-1.2,0.2c-0.3,0.1-0.4,0.4-0.4,0.8c0,0.4,0.1,0.6,0.4,0.8c0.3,0.1,0.6,0.2,1.2,0.2L103,25.5
|
||||
L103,25.5z"/>
|
||||
</g>
|
||||
<g class="st3">
|
||||
<path class="st4" d="M57.5,36.6v5h-1.4v-2.7v-0.7l0.1-0.4v-0.4h-0.1l-0.2,0.3l-0.2,0.3l-0.4,0.7l-1.7,2.8h-1.3l-1.7-2.8l-0.4-0.7
|
||||
l-0.2-0.3l-0.2-0.3h-0.1l0,0.4v0.4l0.1,0.7v2.7h-1.5v-5h2.4l1.4,2.3l0.4,0.7l0.2,0.3l0.2,0.3H53l0.2-0.3l0.2-0.3l0.4-0.7l1.4-2.3
|
||||
L57.5,36.6L57.5,36.6z"/>
|
||||
<path class="st4" d="M63.6,40.6h-3.3l-0.5,0.9h-1.6l2.6-5H63l2.6,5H64L63.6,40.6z M63.2,39.9l-1.3-2.6l-1.3,2.6H63.2z"/>
|
||||
<path class="st4" d="M66.2,41.6v-5H70c1,0,1.8,0.2,2.2,0.5s0.7,0.8,0.7,1.6c0,0.7,0,1.2-0.1,1.5c0,0.3-0.2,0.6-0.5,0.9
|
||||
c-0.3,0.3-1,0.5-2.3,0.5H66.2L66.2,41.6z M67.7,40.7h2.1c0.7,0,1.2-0.1,1.4-0.3s0.3-0.7,0.3-1.4c0-0.7-0.1-1.2-0.3-1.4
|
||||
s-0.6-0.3-1.3-0.3h-2.2L67.7,40.7L67.7,40.7z"/>
|
||||
<path class="st4" d="M75.3,37.4v1.3h3.6v0.7h-3.6v1.4h3.8v0.8h-5.3v-5h5.3v0.8L75.3,37.4L75.3,37.4z"/>
|
||||
<path class="st4" d="M84.4,37.4v1.3H88v0.7h-3.6v1.4h3.8v0.8H83v-5h5.3v0.8L84.4,37.4L84.4,37.4z"/>
|
||||
<path class="st4" d="M94,40.6h-3.3l-0.5,0.9h-1.6l2.6-5h2.2l2.6,5h-1.5L94,40.6z M93.7,39.9l-1.3-2.6L91,39.9H93.7z"/>
|
||||
<path class="st4" d="M102.4,38.1H101v-0.1c0-0.3-0.1-0.4-0.3-0.5c-0.2-0.1-0.6-0.1-1.2-0.1c-0.7,0-1.2,0-1.4,0.1
|
||||
c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.3,0.1,0.5,0.3,0.6s0.8,0.1,1.7,0.1c1.1,0,1.9,0.1,2.2,0.3c0.3,0.2,0.5,0.5,0.5,1.1
|
||||
c0,0.7-0.2,1.1-0.6,1.3s-1.2,0.3-2.5,0.3c-1.3,0-2.2-0.1-2.5-0.3c-0.4-0.2-0.6-0.6-0.6-1.2V40h1.4v0.1c0,0.3,0.1,0.5,0.3,0.6
|
||||
c0.2,0.1,0.7,0.1,1.5,0.1c0.7,0,1.1,0,1.2-0.1s0.3-0.3,0.3-0.6c0-0.3-0.1-0.4-0.2-0.5c-0.1-0.1-0.4-0.1-0.9-0.1l-0.8,0
|
||||
c-1.2,0-2-0.1-2.3-0.3c-0.4-0.2-0.5-0.6-0.5-1.1c0-0.6,0.2-1,0.6-1.2c0.4-0.2,1.2-0.3,2.5-0.3c1.1,0,1.9,0.1,2.3,0.3
|
||||
c0.4,0.2,0.6,0.5,0.6,1L102.4,38.1L102.4,38.1z"/>
|
||||
<path class="st4" d="M110,36.6l-2.9,3.1v1.9h-1.5v-1.9l-2.8-3.1h1.7l1.2,1.3l0.3,0.4l0.2,0.2l0.2,0.2l0.2-0.2l0.2-0.2l0.3-0.4
|
||||
l1.2-1.3H110z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.2 KiB |
@@ -41,7 +41,6 @@
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "A project with this name already exists.",
|
||||
"no-mobile": " To use Infisical, please log in through a device with larger dimensions. ",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"first-name": "First Name",
|
||||
@@ -290,7 +289,7 @@
|
||||
}
|
||||
},
|
||||
"project": {
|
||||
"title": "Settings",
|
||||
"title": "Project Settings",
|
||||
"description": "These settings only apply to the currently selected Project.",
|
||||
"danger-zone": "Danger Zone",
|
||||
"delete-project": "Delete Project",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "Ya existe un proyecto con este nombre.",
|
||||
"no-mobile": "Para usar Infisical, inicia sesión con un dispositivo de mayores dimesiones.",
|
||||
"email": "Correo electrónico",
|
||||
"password": "Contraseña",
|
||||
"first-name": "Nombre",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "Un projet avec ce nom existe déjà.",
|
||||
"no-mobile": " Pour utiliser Infisical, veuillez vous connecter avec un appareil avec des dimensions plus grandes. ",
|
||||
"email": "Email",
|
||||
"password": "Mot de passe",
|
||||
"first-name": "Prénom",
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "동일한 이름을 가진 프로젝트가 이미 존재해요.",
|
||||
"no-mobile": " Infisical을 사용하려면, 큰 화면을 가진 디바이스로 로그인하여 주세요.",
|
||||
"email": "메일",
|
||||
"password": "비밀번호",
|
||||
"first-name": "이름",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "Já exite um projeto com este nome.",
|
||||
"no-mobile": "Para usar o Infisical, faça o login através de um dispositivo com dimensões maiores.",
|
||||
"email": "Email",
|
||||
"password": "Senha",
|
||||
"first-name": "Primeiro Nome",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"common": {
|
||||
"head-title": "{{title}} | Infisical",
|
||||
"error_project-already-exists": "Bu isimle bir proje zaten mevcut.",
|
||||
"no-mobile": " Infisical'ı kullanmak için, lütfen daha büyük boyutlara sahip bir cihaz üzerinden giriş yapın. ",
|
||||
"email": "Email",
|
||||
"password": "Şifre",
|
||||
"first-name": "Adınız",
|
||||
|
||||
@@ -20,9 +20,14 @@ export default function TeamInviteStep(): JSX.Element {
|
||||
const { mutateAsync } = useAddUsersToOrg();
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(["setUpEmail"] as const);
|
||||
|
||||
const orgId = String(localStorage.getItem("orgData.id"));
|
||||
|
||||
// Redirect user to the getting started page
|
||||
const redirectToHome = async () => {
|
||||
navigate({ to: "/organization/projects" as const });
|
||||
navigate({
|
||||
to: orgId ? ("/organizations/$orgId/projects" as const) : "/",
|
||||
params: { orgId }
|
||||
});
|
||||
};
|
||||
|
||||
const inviteUsers = async ({ emails: inviteEmails }: { emails: string }) => {
|
||||
@@ -32,7 +37,7 @@ export default function TeamInviteStep(): JSX.Element {
|
||||
.map(async (email) => {
|
||||
mutateAsync({
|
||||
inviteeEmails: [email],
|
||||
organizationId: String(localStorage.getItem("orgData.id")),
|
||||
organizationId: orgId,
|
||||
organizationRoleSlug: "member"
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,7 +70,8 @@ export default function NavHeader({
|
||||
{currentOrg?.name?.charAt(0)}
|
||||
</div>
|
||||
<Link
|
||||
to="/organization/projects"
|
||||
to="/organizations/$orgId/projects"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
className="truncate pl-0.5 text-sm font-medium text-primary/80 hover:text-primary"
|
||||
>
|
||||
{currentOrg?.name}
|
||||
@@ -90,8 +91,8 @@ export default function NavHeader({
|
||||
<FontAwesomeIcon icon={faAngleRight} className="mr-3 ml-3 text-sm text-gray-400" />
|
||||
{pageName === "Secrets" ? (
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/overview"
|
||||
params={{ projectId: currentProject.id }}
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/overview"
|
||||
params={{ orgId: currentOrg?.id || "", projectId: currentProject.id }}
|
||||
className="text-sm font-medium text-primary/80 hover:text-primary"
|
||||
>
|
||||
{pageName}
|
||||
@@ -126,8 +127,8 @@ export default function NavHeader({
|
||||
<div className="flex items-center space-x-3">
|
||||
<FontAwesomeIcon icon={faAngleRight} className="mr-1.5 ml-3 text-xs text-gray-400" />
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{ projectId: currentProject.id, envSlug: routerEnvSlug }}
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{ orgId: currentOrg.id, projectId: currentProject.id, envSlug: routerEnvSlug }}
|
||||
className="text-sm font-medium text-primary/80 hover:text-primary"
|
||||
>
|
||||
{userAvailableEnvs?.find(({ slug }) => slug === currentEnv)?.name}
|
||||
@@ -188,8 +189,9 @@ export default function NavHeader({
|
||||
</div>
|
||||
) : (
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{
|
||||
orgId: currentOrg?.id || "",
|
||||
projectId: currentProject.id,
|
||||
envSlug: routerEnvSlug || ""
|
||||
}}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useOrganization } from "@app/context";
|
||||
import { useTimedReset } from "@app/hooks";
|
||||
|
||||
import { createNotification } from "../notifications";
|
||||
@@ -23,6 +24,7 @@ export const SecretDashboardPathBreadcrumb = ({
|
||||
projectId,
|
||||
disableCopy
|
||||
}: Props) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const [, isCopying, setIsCopying] = useTimedReset({
|
||||
initialState: false
|
||||
});
|
||||
@@ -69,8 +71,9 @@ export const SecretDashboardPathBreadcrumb = ({
|
||||
</div>
|
||||
) : (
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId,
|
||||
envSlug: environmentSlug
|
||||
}}
|
||||
|
||||
@@ -57,7 +57,8 @@ export const CreateOrgModal: FC<CreateOrgModalProps> = ({ isOpen, onClose }) =>
|
||||
});
|
||||
|
||||
navigate({
|
||||
to: "/organization/projects"
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: organization.id }
|
||||
});
|
||||
|
||||
localStorage.setItem("orgData.id", organization.id);
|
||||
|
||||
@@ -87,17 +87,24 @@ const shouldShowConditionalAccess = (
|
||||
folderPath: string,
|
||||
conditionalFields: string[]
|
||||
): boolean => {
|
||||
return actionRuleMap.some((rule) => {
|
||||
// Find all rules that apply to this environment/path
|
||||
const applicableRules = actionRuleMap.filter((rule) => {
|
||||
const ruleConditions = rule[action]?.conditions;
|
||||
if (!ruleConditions) return false;
|
||||
|
||||
// Check if any of the conditional fields are present
|
||||
const hasConditionalField = conditionalFields.some((field) => ruleConditions[field]);
|
||||
if (!hasConditionalField) return false;
|
||||
|
||||
// Check if base conditions (environment and secretPath) apply
|
||||
return doBaseConditionsApply(ruleConditions, environment, folderPath);
|
||||
});
|
||||
|
||||
// If no rules apply, don't show conditional
|
||||
if (applicableRules.length === 0) return false;
|
||||
|
||||
// Check if ALL applicable rules have conditional fields and if at least one rule applies without conditional fields, show full access
|
||||
const allRulesHaveConditionalFields = applicableRules.every((rule) => {
|
||||
const ruleConditions = rule[action]?.conditions;
|
||||
if (!ruleConditions) return false;
|
||||
return conditionalFields.some((field) => ruleConditions[field]);
|
||||
});
|
||||
|
||||
return allRulesHaveConditionalFields;
|
||||
};
|
||||
|
||||
const determineAccessLevel = (
|
||||
|
||||
@@ -64,7 +64,7 @@ export const CreatePkiSyncModal = ({
|
||||
"Add Sync"
|
||||
)
|
||||
}
|
||||
className="max-w-2xl"
|
||||
className="max-w-3xl"
|
||||
bodyClassName="overflow-visible"
|
||||
subTitle={
|
||||
selectedSync ? undefined : "Select a third-party service to sync certificates to."
|
||||
|
||||
@@ -15,11 +15,13 @@ type Props = {
|
||||
export const EditPkiSyncModal = ({ pkiSync, onOpenChange, fields, ...props }: Props) => {
|
||||
if (!pkiSync) return null;
|
||||
|
||||
const modalClassName = fields === PkiSyncEditFields.Mappings ? "max-w-4xl" : "max-w-2xl";
|
||||
|
||||
return (
|
||||
<Modal {...props} onOpenChange={onOpenChange}>
|
||||
<ModalContent
|
||||
title={<PkiSyncModalHeader isConfigured destination={pkiSync.destination} />}
|
||||
className="max-w-2xl"
|
||||
className={modalClassName}
|
||||
bodyClassName="overflow-visible"
|
||||
>
|
||||
<EditPkiSyncForm onComplete={() => onOpenChange(false)} fields={fields} pkiSync={pkiSync} />
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { FormControl, Select, SelectItem } from "@app/components/v2";
|
||||
import { AWS_REGIONS } from "@app/helpers/appConnections";
|
||||
import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { TPkiSyncForm } from "./schemas/pki-sync-schema";
|
||||
import { PkiSyncConnectionField } from "./PkiSyncConnectionField";
|
||||
|
||||
export const AwsSecretsManagerPkiSyncFields = () => {
|
||||
const { control, setValue } = useFormContext<
|
||||
TPkiSyncForm & { destination: PkiSync.AwsSecretsManager }
|
||||
>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<PkiSyncConnectionField
|
||||
onChange={() => {
|
||||
setValue("destinationConfig.region", "");
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
name="destinationConfig.region"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="AWS Region"
|
||||
tooltipText="Select the AWS region where your secrets will be stored in AWS Secrets Manager."
|
||||
>
|
||||
<Select
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
className="w-full border border-mineshaft-500 capitalize"
|
||||
position="popper"
|
||||
placeholder="Select an AWS region"
|
||||
>
|
||||
{AWS_REGIONS.map(({ name, slug }) => (
|
||||
<SelectItem value={slug} key={slug}>
|
||||
{name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { FormControl, Input } from "@app/components/v2";
|
||||
import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { TPkiSyncForm } from "./schemas/pki-sync-schema";
|
||||
import { PkiSyncConnectionField } from "./PkiSyncConnectionField";
|
||||
|
||||
export const ChefPkiSyncFields = () => {
|
||||
const { control, setValue } = useFormContext<TPkiSyncForm & { destination: PkiSync.Chef }>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<PkiSyncConnectionField
|
||||
onChange={() => {
|
||||
setValue("destinationConfig.dataBagName", "");
|
||||
}}
|
||||
/>
|
||||
<Controller
|
||||
name="destinationConfig.dataBagName"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Data Bag Name"
|
||||
tooltipText="Enter your Chef data bag name where certificates will be stored. This data bag will be used to store SSL/TLS certificates, private keys, and certificate chains. Data bag names must contain only alphanumeric characters, underscores, and hyphens."
|
||||
>
|
||||
<Input {...field} placeholder="ssl_certificates" maxLength={255} />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -4,7 +4,6 @@ import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Tab } from "@headlessui/react";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FormControl, Switch } from "@app/components/v2";
|
||||
@@ -16,6 +15,7 @@ import { PkiSyncFormSchema, TPkiSyncForm } from "./schemas/pki-sync-schema";
|
||||
import { PkiSyncCertificatesFields } from "./PkiSyncCertificatesFields";
|
||||
import { PkiSyncDestinationFields } from "./PkiSyncDestinationFields";
|
||||
import { PkiSyncDetailsFields } from "./PkiSyncDetailsFields";
|
||||
import { PkiSyncFieldMappingsFields } from "./PkiSyncFieldMappingsFields";
|
||||
import { PkiSyncOptionsFields } from "./PkiSyncOptionsFields";
|
||||
import { PkiSyncReviewFields } from "./PkiSyncReviewFields";
|
||||
|
||||
@@ -26,13 +26,38 @@ type Props = {
|
||||
initialData?: any;
|
||||
};
|
||||
|
||||
const FORM_TABS: { name: string; key: string; fields: (keyof TPkiSyncForm)[] }[] = [
|
||||
{ name: "Destination", key: "destination", fields: ["connection", "destinationConfig"] },
|
||||
{ name: "Sync Options", key: "options", fields: ["syncOptions"] },
|
||||
{ name: "Details", key: "details", fields: ["name", "description"] },
|
||||
{ name: "Certificates", key: "certificates", fields: ["certificateIds"] },
|
||||
{ name: "Review", key: "review", fields: [] }
|
||||
];
|
||||
const getFormTabs = (
|
||||
destination: PkiSync
|
||||
): { name: string; key: string; fields: (keyof TPkiSyncForm)[] }[] => {
|
||||
const baseTabs = [
|
||||
{
|
||||
name: "Destination",
|
||||
key: "destination",
|
||||
fields: ["connection", "destinationConfig"] as (keyof TPkiSyncForm)[]
|
||||
},
|
||||
{ name: "Sync Options", key: "options", fields: ["syncOptions"] as (keyof TPkiSyncForm)[] }
|
||||
];
|
||||
|
||||
if (destination === PkiSync.Chef || destination === PkiSync.AwsSecretsManager) {
|
||||
baseTabs.push({
|
||||
name: "Mappings",
|
||||
key: "mappings",
|
||||
fields: ["syncOptions"] as (keyof TPkiSyncForm)[]
|
||||
});
|
||||
}
|
||||
|
||||
baseTabs.push(
|
||||
{ name: "Details", key: "details", fields: ["name", "description"] as (keyof TPkiSyncForm)[] },
|
||||
{
|
||||
name: "Certificates",
|
||||
key: "certificates",
|
||||
fields: ["certificateIds"] as (keyof TPkiSyncForm)[]
|
||||
},
|
||||
{ name: "Review", key: "review", fields: [] as (keyof TPkiSyncForm)[] }
|
||||
);
|
||||
|
||||
return baseTabs;
|
||||
};
|
||||
|
||||
export const CreatePkiSyncForm = ({ destination, onComplete, onCancel, initialData }: Props) => {
|
||||
const createPkiSync = useCreatePkiSync();
|
||||
@@ -42,6 +67,7 @@ export const CreatePkiSyncForm = ({ destination, onComplete, onCancel, initialDa
|
||||
const [showConfirmation, setShowConfirmation] = useState(false);
|
||||
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||
const FORM_TABS = getFormTabs(destination);
|
||||
|
||||
const { syncOption } = usePkiSyncOption(destination);
|
||||
|
||||
@@ -55,7 +81,19 @@ export const CreatePkiSyncForm = ({ destination, onComplete, onCancel, initialDa
|
||||
canImportCertificates: false,
|
||||
canRemoveCertificates: false,
|
||||
preserveArn: true,
|
||||
certificateNameSchema: syncOption?.defaultCertificateNameSchema
|
||||
certificateNameSchema: syncOption?.defaultCertificateNameSchema,
|
||||
...((destination === PkiSync.Chef || destination === PkiSync.AwsSecretsManager) && {
|
||||
fieldMappings: {
|
||||
certificate: "certificate",
|
||||
privateKey: "private_key",
|
||||
certificateChain: "certificate_chain",
|
||||
caCertificate: "ca_certificate"
|
||||
}
|
||||
}),
|
||||
...(destination === PkiSync.AwsSecretsManager && {
|
||||
preserveSecretOnRenewal: true,
|
||||
updateExistingCertificates: true
|
||||
})
|
||||
},
|
||||
...initialData
|
||||
} as Partial<TPkiSyncForm>,
|
||||
@@ -167,10 +205,10 @@ export const CreatePkiSyncForm = ({ destination, onComplete, onCancel, initialDa
|
||||
);
|
||||
|
||||
return (
|
||||
<form className={twMerge(isFinalStep && "max-h-[70vh] overflow-y-auto")}>
|
||||
<form className="flex max-h-[70vh] flex-col overflow-hidden">
|
||||
<FormProvider {...formMethods}>
|
||||
<Tab.Group selectedIndex={selectedTabIndex} onChange={setSelectedTabIndex}>
|
||||
<Tab.List className="-pb-1 mb-6 w-full border-b-2 border-mineshaft-600">
|
||||
<Tab.List className="-pb-1 mb-6 w-full flex-shrink-0 border-b-2 border-mineshaft-600">
|
||||
{FORM_TABS.map((tab, index) => (
|
||||
<Tab
|
||||
onClick={async (e) => {
|
||||
@@ -191,11 +229,11 @@ export const CreatePkiSyncForm = ({ destination, onComplete, onCancel, initialDa
|
||||
</Tab>
|
||||
))}
|
||||
</Tab.List>
|
||||
<Tab.Panels>
|
||||
<Tab.Panel>
|
||||
<Tab.Panels className="flex-1 overflow-y-auto">
|
||||
<Tab.Panel className="max-h-full overflow-y-auto">
|
||||
<PkiSyncDestinationFields />
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>
|
||||
<Tab.Panel className="max-h-full overflow-y-auto">
|
||||
<PkiSyncOptionsFields destination={destination} />
|
||||
<Controller
|
||||
control={control}
|
||||
@@ -225,20 +263,25 @@ export const CreatePkiSyncForm = ({ destination, onComplete, onCancel, initialDa
|
||||
}}
|
||||
/>
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>
|
||||
{(destination === PkiSync.Chef || destination === PkiSync.AwsSecretsManager) && (
|
||||
<Tab.Panel className="max-h-full overflow-y-auto">
|
||||
<PkiSyncFieldMappingsFields destination={destination} />
|
||||
</Tab.Panel>
|
||||
)}
|
||||
<Tab.Panel className="max-h-full overflow-y-auto">
|
||||
<PkiSyncDetailsFields />
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>
|
||||
<Tab.Panel className="max-h-full overflow-y-auto">
|
||||
<PkiSyncCertificatesFields />
|
||||
</Tab.Panel>
|
||||
<Tab.Panel>
|
||||
<Tab.Panel className="max-h-full overflow-y-auto">
|
||||
<PkiSyncReviewFields />
|
||||
</Tab.Panel>
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</FormProvider>
|
||||
|
||||
<div className="flex w-full flex-row-reverse justify-between gap-4 pt-4">
|
||||
<div className="mt-4 flex w-full flex-shrink-0 flex-row-reverse justify-between gap-4 border-t border-mineshaft-600 pt-4">
|
||||
<Button onClick={handleNext} colorSchema="secondary">
|
||||
{isFinalStep ? "Create Sync" : "Next"}
|
||||
</Button>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { TPkiSync, useUpdatePkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
import { TUpdatePkiSyncForm, UpdatePkiSyncFormSchema } from "./schemas/pki-sync-schema";
|
||||
import { PkiSyncDestinationFields } from "./PkiSyncDestinationFields";
|
||||
import { PkiSyncDetailsFields } from "./PkiSyncDetailsFields";
|
||||
import { PkiSyncFieldMappingsFields } from "./PkiSyncFieldMappingsFields";
|
||||
import { PkiSyncOptionsFields } from "./PkiSyncOptionsFields";
|
||||
import { PkiSyncSourceFields } from "./PkiSyncSourceFields";
|
||||
|
||||
@@ -66,6 +67,9 @@ export const EditPkiSyncForm = ({ pkiSync, fields, onComplete }: Props) => {
|
||||
case PkiSyncEditFields.Options:
|
||||
Component = <PkiSyncOptionsFields destination={pkiSync.destination} />;
|
||||
break;
|
||||
case PkiSyncEditFields.Mappings:
|
||||
Component = <PkiSyncFieldMappingsFields destination={pkiSync.destination} />;
|
||||
break;
|
||||
case PkiSyncEditFields.Source:
|
||||
Component = <PkiSyncSourceFields />;
|
||||
break;
|
||||
|
||||
@@ -4,7 +4,9 @@ import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { TPkiSyncForm } from "./schemas/pki-sync-schema";
|
||||
import { AwsCertificateManagerPkiSyncFields } from "./AwsCertificateManagerPkiSyncFields";
|
||||
import { AwsSecretsManagerPkiSyncFields } from "./AwsSecretsManagerPkiSyncFields";
|
||||
import { AzureKeyVaultPkiSyncFields } from "./AzureKeyVaultPkiSyncFields";
|
||||
import { ChefPkiSyncFields } from "./ChefPkiSyncFields";
|
||||
|
||||
export const PkiSyncDestinationFields = () => {
|
||||
const { watch } = useFormContext<TPkiSyncForm>();
|
||||
@@ -16,6 +18,10 @@ export const PkiSyncDestinationFields = () => {
|
||||
return <AzureKeyVaultPkiSyncFields />;
|
||||
case PkiSync.AwsCertificateManager:
|
||||
return <AwsCertificateManagerPkiSyncFields />;
|
||||
case PkiSync.AwsSecretsManager:
|
||||
return <AwsSecretsManagerPkiSyncFields />;
|
||||
case PkiSync.Chef:
|
||||
return <ChefPkiSyncFields />;
|
||||
default:
|
||||
return (
|
||||
<div className="flex items-center justify-center rounded-md border border-red-500 bg-red-100 p-4 text-red-700">
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { FormControl, Input } from "@app/components/v2";
|
||||
import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { TPkiSyncForm } from "./schemas/pki-sync-schema";
|
||||
|
||||
type Props = {
|
||||
destination?: PkiSync;
|
||||
};
|
||||
|
||||
export const PkiSyncFieldMappingsFields = ({ destination }: Props) => {
|
||||
const { control, watch } = useFormContext<TPkiSyncForm>();
|
||||
const currentDestination = destination || watch("destination");
|
||||
|
||||
if (currentDestination !== PkiSync.Chef && currentDestination !== PkiSync.AwsSecretsManager) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="mb-4 text-sm text-bunker-300">
|
||||
Configure how certificate fields are mapped to your{" "}
|
||||
{currentDestination === PkiSync.Chef ? "Chef data bag items" : "AWS secrets"}.
|
||||
</p>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.fieldMappings.certificate"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Certificate Field"
|
||||
tooltipText={`The field name used to store the certificate content in the ${currentDestination === PkiSync.Chef ? "Chef data bag item" : "AWS secret"}.`}
|
||||
>
|
||||
<Input {...field} placeholder="certificate" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.fieldMappings.privateKey"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Private Key Field"
|
||||
tooltipText={`The field name used to store the private key content in the ${currentDestination === PkiSync.Chef ? "Chef data bag item" : "AWS secret"}.`}
|
||||
>
|
||||
<Input {...field} placeholder="private_key" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.fieldMappings.certificateChain"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="Certificate Chain Field"
|
||||
tooltipText={`The field name used to store the certificate chain content in the ${currentDestination === PkiSync.Chef ? "Chef data bag item" : "AWS secret"}.`}
|
||||
>
|
||||
<Input {...field} placeholder="certificate_chain" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.fieldMappings.caCertificate"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
label="CA Certificate Field"
|
||||
tooltipText={`The field name used to store the CA certificate content in the ${currentDestination === PkiSync.Chef ? "Chef data bag item" : "AWS secret"}.`}
|
||||
>
|
||||
<Input {...field} placeholder="ca_certificate" />
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||
<h4 className="mb-2 text-sm font-medium text-mineshaft-100">Preview JSON Structure</h4>
|
||||
<pre className="text-xs text-bunker-300">
|
||||
{`{
|
||||
"id": "certificate-item-name",
|
||||
"${watch("syncOptions.fieldMappings.certificate") || "certificate"}": "<certificate-content>",
|
||||
"${watch("syncOptions.fieldMappings.privateKey") || "private_key"}": "<private-key-content>",
|
||||
"${watch("syncOptions.fieldMappings.certificateChain") || "certificate_chain"}": "<certificate-chain-content>",
|
||||
"${watch("syncOptions.fieldMappings.caCertificate") || "ca_certificate"}": "<ca-certificate-content>"
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
+133
@@ -95,6 +95,48 @@ export const PkiSyncOptionsFields = ({ destination }: Props) => {
|
||||
)}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.includeRootCa"
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
className="bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
id="include-root-ca"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={value}
|
||||
>
|
||||
<p>
|
||||
Include Root CA in Certificate Chain{" "}
|
||||
<Tooltip
|
||||
className="max-w-md"
|
||||
content={
|
||||
<>
|
||||
<p>
|
||||
When enabled, the full certificate chain including the root CA will be
|
||||
synced to the destination.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
When disabled, the root CA will be excluded from the certificate chain
|
||||
during sync operations, reducing the size of the synced certificate chain.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
Most applications and services work correctly with intermediate certificates
|
||||
only, as they can validate the trust chain up to a root CA they already
|
||||
trust.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
|
||||
</Tooltip>
|
||||
</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
|
||||
{currentDestination === PkiSync.AwsCertificateManager && (
|
||||
<Controller
|
||||
control={control}
|
||||
@@ -183,6 +225,97 @@ export const PkiSyncOptionsFields = ({ destination }: Props) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentDestination === PkiSync.AwsSecretsManager && (
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.preserveSecretOnRenewal"
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
className="bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
id="preserve-secret-on-renewal"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={value}
|
||||
>
|
||||
<p>
|
||||
Preserve Secret on Renewal{" "}
|
||||
<Tooltip
|
||||
className="max-w-md"
|
||||
content={
|
||||
<>
|
||||
<p>
|
||||
<strong>Only applies to certificate renewals:</strong> When a certificate
|
||||
is renewed in Infisical, this option controls how the renewed certificate
|
||||
is handled in AWS Secrets Manager.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
When enabled, the renewed certificate will update the existing secret,
|
||||
preserving the same secret name and ARN. This allows consuming services to
|
||||
continue using the same secret reference without requiring updates.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
When disabled, the renewed certificate will be created as a new secret
|
||||
with a new name, and the old secret will be removed.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
|
||||
</Tooltip>
|
||||
</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentDestination === PkiSync.Chef && (
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.preserveItemOnRenewal"
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message}>
|
||||
<Switch
|
||||
className="bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
id="preserve-item-on-renewal"
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={value}
|
||||
>
|
||||
<p>
|
||||
Preserve Data Bag Item on Renewal{" "}
|
||||
<Tooltip
|
||||
className="max-w-md"
|
||||
content={
|
||||
<>
|
||||
<p>
|
||||
<strong>Only applies to certificate renewals:</strong> When a certificate
|
||||
is renewed in Infisical, this option controls how the renewed certificate
|
||||
is handled in Chef.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
When enabled, the renewed certificate will update the existing data bag
|
||||
item, preserving the same item name. This allows consuming services to
|
||||
continue using the same data bag item without requiring updates to Chef
|
||||
cookbooks or recipes.
|
||||
</p>
|
||||
<p className="mt-4">
|
||||
When disabled, the renewed certificate will be created as a new data bag
|
||||
item with a new name, and the old item will be removed.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
|
||||
</Tooltip>
|
||||
</p>
|
||||
</Switch>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="syncOptions.certificateNameSchema"
|
||||
|
||||
+1
@@ -7,6 +7,7 @@ import { BasePkiSyncSchema } from "./base-pki-sync-schema";
|
||||
const AwsCertificateManagerSyncOptionsSchema = z.object({
|
||||
canImportCertificates: z.boolean().default(false),
|
||||
canRemoveCertificates: z.boolean().default(false),
|
||||
includeRootCa: z.boolean().default(false),
|
||||
preserveArn: z.boolean().default(true),
|
||||
certificateNameSchema: z
|
||||
.string()
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { BasePkiSyncSchema } from "./base-pki-sync-schema";
|
||||
|
||||
const AwsSecretsManagerFieldMappingsSchema = z.object({
|
||||
certificate: z.string().min(1, "Certificate field name is required").default("certificate"),
|
||||
privateKey: z.string().min(1, "Private key field name is required").default("private_key"),
|
||||
certificateChain: z
|
||||
.string()
|
||||
.min(1, "Certificate chain field name is required")
|
||||
.default("certificate_chain"),
|
||||
caCertificate: z
|
||||
.string()
|
||||
.min(1, "CA certificate field name is required")
|
||||
.default("ca_certificate")
|
||||
});
|
||||
|
||||
const AwsSecretsManagerSyncOptionsSchema = z.object({
|
||||
canImportCertificates: z.boolean().default(false),
|
||||
canRemoveCertificates: z.boolean().default(true),
|
||||
includeRootCa: z.boolean().default(false),
|
||||
preserveSecretOnRenewal: z.boolean().default(true),
|
||||
updateExistingCertificates: z.boolean().default(true),
|
||||
certificateNameSchema: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(
|
||||
(val) => {
|
||||
if (!val) return true;
|
||||
|
||||
const allowedOptionalPlaceholders = [
|
||||
"{{environment}}",
|
||||
"{{profileId}}",
|
||||
"{{commonName}}",
|
||||
"{{friendlyName}}"
|
||||
];
|
||||
|
||||
const allowedPlaceholdersRegexPart = ["{{certificateId}}", ...allowedOptionalPlaceholders]
|
||||
.map((p) => p.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"))
|
||||
.join("|");
|
||||
|
||||
const allowedContentRegex = new RegExp(
|
||||
`^([a-zA-Z0-9_\\-]|${allowedPlaceholdersRegexPart})*$`
|
||||
);
|
||||
const contentIsValid = allowedContentRegex.test(val);
|
||||
|
||||
if (val.trim()) {
|
||||
const certificateIdRegex = /\{\{certificateId\}\}/;
|
||||
const certificateIdIsPresent = certificateIdRegex.test(val);
|
||||
return contentIsValid && certificateIdIsPresent;
|
||||
}
|
||||
|
||||
return contentIsValid;
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Certificate name schema must include exactly one {{certificateId}} placeholder. It can also include {{environment}}, {{profileId}}, {{commonName}}, or {{friendlyName}} placeholders. Only alphanumeric characters (a-z, A-Z, 0-9), hyphens (-), and underscores (_) are allowed besides the placeholders."
|
||||
}
|
||||
),
|
||||
fieldMappings: AwsSecretsManagerFieldMappingsSchema.optional().default({
|
||||
certificate: "certificate",
|
||||
privateKey: "private_key",
|
||||
certificateChain: "certificate_chain",
|
||||
caCertificate: "ca_certificate"
|
||||
})
|
||||
});
|
||||
|
||||
export const AwsSecretsManagerPkiSyncDestinationSchema = BasePkiSyncSchema(
|
||||
AwsSecretsManagerSyncOptionsSchema
|
||||
).merge(
|
||||
z.object({
|
||||
destination: z.literal(PkiSync.AwsSecretsManager),
|
||||
destinationConfig: z.object({
|
||||
region: z.string().min(1, "AWS region is required")
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
export const UpdateAwsSecretsManagerPkiSyncDestinationSchema =
|
||||
AwsSecretsManagerPkiSyncDestinationSchema.partial().merge(
|
||||
z.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Name is required")
|
||||
.max(255, "Name must be less than 255 characters"),
|
||||
destination: z.literal(PkiSync.AwsSecretsManager),
|
||||
connection: z.object({
|
||||
id: z.string().uuid("Invalid connection ID format"),
|
||||
name: z
|
||||
.string()
|
||||
.min(1, "Connection name is required")
|
||||
.max(255, "Connection name must be less than 255 characters")
|
||||
})
|
||||
})
|
||||
);
|
||||
+1
@@ -7,6 +7,7 @@ import { BasePkiSyncSchema } from "./base-pki-sync-schema";
|
||||
const AzureKeyVaultSyncOptionsSchema = z.object({
|
||||
canImportCertificates: z.boolean().default(false),
|
||||
canRemoveCertificates: z.boolean().default(true),
|
||||
includeRootCa: z.boolean().default(false),
|
||||
enableVersioning: z.boolean().default(true),
|
||||
certificateNameSchema: z
|
||||
.string()
|
||||
|
||||
@@ -6,6 +6,7 @@ export const BasePkiSyncSchema = <T extends AnyZodObject | undefined = undefined
|
||||
const baseSyncOptionsSchema = z.object({
|
||||
canImportCertificates: z.boolean().default(false),
|
||||
canRemoveCertificates: z.boolean().default(false),
|
||||
includeRootCa: z.boolean().default(false),
|
||||
certificateNameSchema: z
|
||||
.string()
|
||||
.optional()
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { BasePkiSyncSchema } from "./base-pki-sync-schema";
|
||||
|
||||
const ChefFieldMappingsSchema = z.object({
|
||||
certificate: z.string().min(1, "Certificate field name is required").default("certificate"),
|
||||
privateKey: z.string().min(1, "Private key field name is required").default("private_key"),
|
||||
certificateChain: z
|
||||
.string()
|
||||
.min(1, "Certificate chain field name is required")
|
||||
.default("certificate_chain"),
|
||||
caCertificate: z
|
||||
.string()
|
||||
.min(1, "CA certificate field name is required")
|
||||
.default("ca_certificate")
|
||||
});
|
||||
|
||||
const ChefSyncOptionsSchema = z.object({
|
||||
canImportCertificates: z.boolean().default(false),
|
||||
canRemoveCertificates: z.boolean().default(true),
|
||||
includeRootCa: z.boolean().default(false),
|
||||
preserveItemOnRenewal: z.boolean().default(true),
|
||||
updateExistingCertificates: z.boolean().default(true),
|
||||
certificateNameSchema: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(
|
||||
(val) => {
|
||||
if (!val) return true;
|
||||
|
||||
const allowedOptionalPlaceholders = [
|
||||
"{{environment}}",
|
||||
"{{profileId}}",
|
||||
"{{commonName}}",
|
||||
"{{friendlyName}}"
|
||||
];
|
||||
|
||||
const allowedPlaceholdersRegexPart = ["{{certificateId}}", ...allowedOptionalPlaceholders]
|
||||
.map((p) => p.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"))
|
||||
.join("|");
|
||||
|
||||
const allowedContentRegex = new RegExp(
|
||||
`^([a-zA-Z0-9_\\-]|${allowedPlaceholdersRegexPart})*$`
|
||||
);
|
||||
const contentIsValid = allowedContentRegex.test(val);
|
||||
|
||||
if (val.trim()) {
|
||||
const certificateIdRegex = /\{\{certificateId\}\}/;
|
||||
const certificateIdIsPresent = certificateIdRegex.test(val);
|
||||
return contentIsValid && certificateIdIsPresent;
|
||||
}
|
||||
|
||||
return contentIsValid;
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Certificate item name schema must include exactly one {{certificateId}} placeholder. It can also include {{environment}}, {{profileId}}, {{commonName}}, or {{friendlyName}} placeholders. Only alphanumeric characters (a-z, A-Z, 0-9), hyphens (-), and underscores (_) are allowed besides the placeholders."
|
||||
}
|
||||
),
|
||||
fieldMappings: ChefFieldMappingsSchema.optional().default({
|
||||
certificate: "certificate",
|
||||
privateKey: "private_key",
|
||||
certificateChain: "certificate_chain",
|
||||
caCertificate: "ca_certificate"
|
||||
})
|
||||
});
|
||||
|
||||
export const ChefPkiSyncDestinationSchema = BasePkiSyncSchema(ChefSyncOptionsSchema).merge(
|
||||
z.object({
|
||||
destination: z.literal(PkiSync.Chef),
|
||||
destinationConfig: z.object({
|
||||
dataBagName: z
|
||||
.string()
|
||||
.min(1, "Data bag name is required")
|
||||
.max(255, "Data bag name must be less than 255 characters")
|
||||
.regex(
|
||||
/^[a-zA-Z0-9_-]+$/,
|
||||
"Data bag name can only contain alphanumeric characters, underscores, and hyphens"
|
||||
)
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
export const UpdateChefPkiSyncDestinationSchema = ChefPkiSyncDestinationSchema.partial().merge(
|
||||
z.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Name is required")
|
||||
.max(255, "Name must be less than 255 characters"),
|
||||
destination: z.literal(PkiSync.Chef),
|
||||
connection: z.object({
|
||||
id: z.string().uuid("Invalid connection ID format"),
|
||||
name: z
|
||||
.string()
|
||||
.min(1, "Connection name is required")
|
||||
.max(255, "Connection name must be less than 255 characters")
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -4,19 +4,31 @@ import {
|
||||
AwsCertificateManagerPkiSyncDestinationSchema,
|
||||
UpdateAwsCertificateManagerPkiSyncDestinationSchema
|
||||
} from "./aws-certificate-manager-pki-sync-destination-schema";
|
||||
import {
|
||||
AwsSecretsManagerPkiSyncDestinationSchema,
|
||||
UpdateAwsSecretsManagerPkiSyncDestinationSchema
|
||||
} from "./aws-secrets-manager-pki-sync-destination-schema";
|
||||
import {
|
||||
AzureKeyVaultPkiSyncDestinationSchema,
|
||||
UpdateAzureKeyVaultPkiSyncDestinationSchema
|
||||
} from "./azure-key-vault-pki-sync-destination-schema";
|
||||
import {
|
||||
ChefPkiSyncDestinationSchema,
|
||||
UpdateChefPkiSyncDestinationSchema
|
||||
} from "./chef-pki-sync-destination-schema";
|
||||
|
||||
const PkiSyncUnionSchema = z.discriminatedUnion("destination", [
|
||||
AzureKeyVaultPkiSyncDestinationSchema,
|
||||
AwsCertificateManagerPkiSyncDestinationSchema
|
||||
AwsCertificateManagerPkiSyncDestinationSchema,
|
||||
AwsSecretsManagerPkiSyncDestinationSchema,
|
||||
ChefPkiSyncDestinationSchema
|
||||
]);
|
||||
|
||||
const UpdatePkiSyncUnionSchema = z.discriminatedUnion("destination", [
|
||||
UpdateAzureKeyVaultPkiSyncDestinationSchema,
|
||||
UpdateAwsCertificateManagerPkiSyncDestinationSchema
|
||||
UpdateAwsCertificateManagerPkiSyncDestinationSchema,
|
||||
UpdateAwsSecretsManagerPkiSyncDestinationSchema,
|
||||
UpdateChefPkiSyncDestinationSchema
|
||||
]);
|
||||
|
||||
export const PkiSyncFormSchema = PkiSyncUnionSchema;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export enum PkiSyncEditFields {
|
||||
Details = "details",
|
||||
Options = "options",
|
||||
Mappings = "mappings",
|
||||
Source = "source",
|
||||
Destination = "destination"
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ export const ProjectOverviewChangeSection = ({ showSlugField = false }: Props) =
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="justify-betweens flex">
|
||||
<h2 className="mb-8 flex-1 text-xl font-medium text-mineshaft-100">Project Overview</h2>
|
||||
<div className="justify-betweens mb-8 flex flex-wrap gap-2">
|
||||
<h2 className="flex-1 text-xl font-medium text-mineshaft-100">Project Overview</h2>
|
||||
<div className="space-x-2">
|
||||
<Button
|
||||
variant="outline_bg"
|
||||
|
||||
@@ -157,7 +157,7 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
|
||||
onOpenChange(false);
|
||||
navigate({
|
||||
to: getProjectHomePage(project.type, project.environments),
|
||||
params: { projectId: project.id }
|
||||
params: { projectId: project.id, orgId: currentOrg.id }
|
||||
});
|
||||
};
|
||||
const onSubmit = handleSubmit((data) => {
|
||||
|
||||
@@ -3,14 +3,7 @@ import { ReactNode } from "@tanstack/react-router";
|
||||
import { LucideIcon } from "lucide-react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import {
|
||||
Badge,
|
||||
InstanceIcon,
|
||||
OrgIcon,
|
||||
ProjectIcon,
|
||||
SubOrgIcon,
|
||||
TBadgeProps
|
||||
} from "@app/components/v3";
|
||||
import { InstanceIcon, OrgIcon, ProjectIcon, SubOrgIcon } from "@app/components/v3";
|
||||
import { ProjectType } from "@app/hooks/api/projects/types";
|
||||
|
||||
type Props = {
|
||||
@@ -21,41 +14,40 @@ type Props = {
|
||||
scope: "org" | "namespace" | "instance" | ProjectType | null;
|
||||
};
|
||||
|
||||
const SCOPE_NAME: Record<NonNullable<Props["scope"]>, { label: string; icon: LucideIcon }> = {
|
||||
org: { label: "Organization", icon: OrgIcon },
|
||||
[ProjectType.SecretManager]: { label: "Project", icon: ProjectIcon },
|
||||
[ProjectType.CertificateManager]: { label: "Project", icon: ProjectIcon },
|
||||
[ProjectType.SSH]: { label: "Project", icon: ProjectIcon },
|
||||
[ProjectType.KMS]: { label: "Project", icon: ProjectIcon },
|
||||
[ProjectType.PAM]: { label: "Project", icon: ProjectIcon },
|
||||
[ProjectType.SecretScanning]: { label: "Project", icon: ProjectIcon },
|
||||
namespace: { label: "Sub-Organization", icon: SubOrgIcon },
|
||||
instance: { label: "Server", icon: InstanceIcon }
|
||||
};
|
||||
|
||||
const SCOPE_VARIANT: Record<NonNullable<Props["scope"]>, TBadgeProps["variant"]> = {
|
||||
org: "org",
|
||||
[ProjectType.SecretManager]: "project",
|
||||
[ProjectType.CertificateManager]: "project",
|
||||
[ProjectType.SSH]: "project",
|
||||
[ProjectType.KMS]: "project",
|
||||
[ProjectType.PAM]: "project",
|
||||
[ProjectType.SecretScanning]: "project",
|
||||
namespace: "sub-org",
|
||||
instance: "neutral"
|
||||
const SCOPE_BADGE: Record<NonNullable<Props["scope"]>, { icon: LucideIcon; className: string }> = {
|
||||
org: { className: "text-org", icon: OrgIcon },
|
||||
[ProjectType.SecretManager]: { className: "text-project", icon: ProjectIcon },
|
||||
[ProjectType.CertificateManager]: { className: "text-project", icon: ProjectIcon },
|
||||
[ProjectType.SSH]: { className: "text-project", icon: ProjectIcon },
|
||||
[ProjectType.KMS]: { className: "text-project", icon: ProjectIcon },
|
||||
[ProjectType.PAM]: { className: "text-project", icon: ProjectIcon },
|
||||
[ProjectType.SecretScanning]: { className: "text-project", icon: ProjectIcon },
|
||||
namespace: { className: "text-sub-org", icon: SubOrgIcon },
|
||||
instance: { className: "text-neutral", icon: InstanceIcon }
|
||||
};
|
||||
|
||||
export const PageHeader = ({ title, description, children, className, scope }: Props) => (
|
||||
<div className={twMerge("mb-10 w-full", className)}>
|
||||
<div className="flex w-full justify-between">
|
||||
<div className="mr-4 flex w-full items-center">
|
||||
<h1 className="text-3xl font-medium text-white capitalize">{title}</h1>
|
||||
{scope && (
|
||||
<Badge variant={SCOPE_VARIANT[scope]} className="mt-1 ml-2.5">
|
||||
{createElement(SCOPE_NAME[scope].icon)}
|
||||
{SCOPE_NAME[scope].label}
|
||||
</Badge>
|
||||
)}
|
||||
<h1
|
||||
className={twMerge(
|
||||
"text-3xl font-medium text-white capitalize underline decoration-2 underline-offset-4",
|
||||
scope === "org" && "decoration-org/90",
|
||||
scope === "instance" && "decoration-neutral/90",
|
||||
scope === "namespace" && "decoration-sub-org/90",
|
||||
Object.values(ProjectType).includes((scope as ProjectType) ?? "") &&
|
||||
"decoration-project/90",
|
||||
!scope && "no-underline"
|
||||
)}
|
||||
>
|
||||
{scope &&
|
||||
createElement(SCOPE_BADGE[scope].icon, {
|
||||
size: 26,
|
||||
className: twMerge(SCOPE_BADGE[scope].className, "mr-3 mb-1 inline-block")
|
||||
})}
|
||||
{title}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -47,8 +47,8 @@ export const Tab = ({
|
||||
}) => (
|
||||
<TabsPrimitive.Trigger
|
||||
className={twMerge(
|
||||
"flex h-10 cursor-pointer items-center justify-center border-transparent",
|
||||
"px-3 text-sm font-medium whitespace-nowrap text-mineshaft-400 transition-all select-none",
|
||||
"flex h-11 cursor-pointer items-center justify-center border-transparent",
|
||||
"px-3 text-sm font-medium whitespace-nowrap text-mineshaft-300/75 transition-all select-none",
|
||||
"data-[orientation=vertical]:xl:h-5 data-[orientation=vertical]:xl:border-b-0 data-[orientation=vertical]:xl:border-l",
|
||||
"border-b hover:text-mineshaft-200",
|
||||
"data-[state=active]:border-mineshaft-400 data-[state=active]:text-white",
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { BookOpenIcon } from "lucide-react";
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
|
||||
import { Badge } from "@app/components/v3";
|
||||
|
||||
@@ -8,10 +8,10 @@ type TDocumentationLinkBadgeProps = {
|
||||
|
||||
export function DocumentationLinkBadge({ href }: TDocumentationLinkBadgeProps) {
|
||||
return (
|
||||
<Badge variant="neutral" asChild>
|
||||
<Badge variant="info" asChild>
|
||||
<a href={href} target="_blank" rel="noopener noreferrer">
|
||||
<BookOpenIcon />
|
||||
Documentation
|
||||
<ExternalLinkIcon />
|
||||
</a>
|
||||
</Badge>
|
||||
);
|
||||
|
||||
+162
-162
@@ -25,343 +25,343 @@ export const ROUTE_PATHS = Object.freeze({
|
||||
Organization: {
|
||||
Settings: {
|
||||
OauthCallbackPage: setRoute(
|
||||
"/organization/settings/oauth/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/settings/oauth/callback"
|
||||
"/organizations/$orgId/settings/oauth/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/settings/oauth/callback"
|
||||
)
|
||||
},
|
||||
SecretSharing: setRoute(
|
||||
"/organization/secret-sharing",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/"
|
||||
"/organizations/$orgId/secret-sharing",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/secret-sharing/"
|
||||
),
|
||||
SettingsPage: setRoute(
|
||||
"/organization/settings",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/settings/"
|
||||
"/organizations/$orgId/settings",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/settings/"
|
||||
),
|
||||
GroupDetailsByIDPage: setRoute(
|
||||
"/organization/groups/$groupId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId"
|
||||
"/organizations/$orgId/groups/$groupId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/groups/$groupId"
|
||||
),
|
||||
IdentityDetailsByIDPage: setRoute(
|
||||
"/organization/identities/$identityId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId"
|
||||
"/organizations/$orgId/identities/$identityId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/identities/$identityId"
|
||||
),
|
||||
UserDetailsByIDPage: setRoute(
|
||||
"/organization/members/$membershipId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId"
|
||||
"/organizations/$orgId/members/$membershipId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/members/$membershipId"
|
||||
),
|
||||
AccessControlPage: setRoute(
|
||||
"/organization/access-management",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/access-management"
|
||||
"/organizations/$orgId/access-management",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/access-management"
|
||||
),
|
||||
RoleByIDPage: setRoute(
|
||||
"/organization/roles/$roleId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId"
|
||||
"/organizations/$orgId/roles/$roleId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/roles/$roleId"
|
||||
),
|
||||
AppConnections: {
|
||||
OauthCallbackPage: setRoute(
|
||||
"/organization/app-connections/$appConnection/oauth/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/app-connections/$appConnection/oauth/callback"
|
||||
"/organizations/$orgId/app-connections/$appConnection/oauth/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/app-connections/$appConnection/oauth/callback"
|
||||
)
|
||||
},
|
||||
NetworkingPage: setRoute(
|
||||
"/organization/networking",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organization/networking"
|
||||
"/organizations/$orgId/networking",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/networking"
|
||||
)
|
||||
},
|
||||
SecretManager: {
|
||||
ApprovalPage: setRoute(
|
||||
"/projects/secret-management/$projectId/approval",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/approval"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/approval",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/approval"
|
||||
),
|
||||
SecretDashboardPage: setRoute(
|
||||
"/projects/secret-management/$projectId/secrets/$envSlug",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/secrets/$envSlug"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/secrets/$envSlug"
|
||||
),
|
||||
RollbackPreviewPage: setRoute(
|
||||
"/projects/secret-management/$projectId/commits/$environment/$folderId/$commitId/restore",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/commits/$environment/$folderId/$commitId/restore"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/commits/$environment/$folderId/$commitId/restore",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/commits/$environment/$folderId/$commitId/restore"
|
||||
),
|
||||
CommitDetailsPage: setRoute(
|
||||
"/projects/secret-management/$projectId/commits/$environment/$folderId/$commitId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/commits/$environment/$folderId/$commitId"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/commits/$environment/$folderId/$commitId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/commits/$environment/$folderId/$commitId"
|
||||
),
|
||||
CommitsPage: setRoute(
|
||||
"/projects/secret-management/$projectId/commits/$environment/$folderId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/commits/$environment/$folderId"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/commits/$environment/$folderId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/commits/$environment/$folderId"
|
||||
),
|
||||
OverviewPage: setRoute(
|
||||
"/projects/secret-management/$projectId/overview",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/overview"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/overview",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/overview"
|
||||
),
|
||||
IntegrationsListPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/"
|
||||
),
|
||||
IntegrationDetailsByIDPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/$integrationId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/$integrationId"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/$integrationId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/$integrationId"
|
||||
),
|
||||
SecretSyncDetailsByIDPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/secret-syncs/$destination/$syncId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/secret-syncs/$destination/$syncId"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/secret-syncs/$destination/$syncId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/secret-syncs/$destination/$syncId"
|
||||
),
|
||||
Integratons: {
|
||||
SelectIntegrationAuth: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/select-integration-auth",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/select-integration-auth"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/select-integration-auth",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/select-integration-auth"
|
||||
),
|
||||
HerokuOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/heroku/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/heroku/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/heroku/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/heroku/oauth2/callback"
|
||||
),
|
||||
HerokuConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/heroku/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/heroku/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/heroku/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/heroku/create"
|
||||
),
|
||||
AwsParameterStoreConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/aws-parameter-store/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/aws-parameter-store/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/aws-parameter-store/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/aws-parameter-store/create"
|
||||
),
|
||||
AwsSecretManagerConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/aws-secret-manager/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/aws-secret-manager/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/aws-secret-manager/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/aws-secret-manager/create"
|
||||
),
|
||||
AzureAppConfigurationsOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/azure-app-configuration/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-app-configuration/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/azure-app-configuration/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-app-configuration/oauth2/callback"
|
||||
),
|
||||
AzureAppConfigurationsConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/azure-app-configuration/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-app-configuration/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/azure-app-configuration/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-app-configuration/create"
|
||||
),
|
||||
AzureDevopsConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/azure-devops/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-devops/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/azure-devops/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-devops/create"
|
||||
),
|
||||
AzureKeyVaultAuthorizePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/azure-key-vault/authorize",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-key-vault/authorize"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/azure-key-vault/authorize",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-key-vault/authorize"
|
||||
),
|
||||
AzureKeyVaultOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/azure-key-vault/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-key-vault/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/azure-key-vault/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-key-vault/oauth2/callback"
|
||||
),
|
||||
AzureKeyVaultConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/azure-key-vault/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-key-vault/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/azure-key-vault/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/azure-key-vault/create"
|
||||
),
|
||||
BitbucketOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/bitbucket/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/bitbucket/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/bitbucket/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/bitbucket/oauth2/callback"
|
||||
),
|
||||
BitbucketConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/bitbucket/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/bitbucket/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/bitbucket/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/bitbucket/create"
|
||||
),
|
||||
ChecklyConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/checkly/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/checkly/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/checkly/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/checkly/create"
|
||||
),
|
||||
CircleConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/circleci/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/circleci/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/circleci/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/circleci/create"
|
||||
),
|
||||
CloudflarePagesConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/cloudflare-pages/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/cloudflare-pages/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/cloudflare-pages/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/cloudflare-pages/create"
|
||||
),
|
||||
DigitalOceanAppPlatformConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/digital-ocean-app-platform/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/digital-ocean-app-platform/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/digital-ocean-app-platform/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/digital-ocean-app-platform/create"
|
||||
),
|
||||
CloudflareWorkersConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/cloudflare-workers/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/cloudflare-workers/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/cloudflare-workers/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/cloudflare-workers/create"
|
||||
),
|
||||
CodefreshConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/codefresh/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/codefresh/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/codefresh/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/codefresh/create"
|
||||
),
|
||||
GcpSecretManagerConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/gcp-secret-manager/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/gcp-secret-manager/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/gcp-secret-manager/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/gcp-secret-manager/create"
|
||||
),
|
||||
GcpSecretManagerOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/gcp-secret-manager/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/gcp-secret-manager/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/gcp-secret-manager/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/gcp-secret-manager/oauth2/callback"
|
||||
),
|
||||
GithubConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/github/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/github/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/github/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/github/create"
|
||||
),
|
||||
GithubOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/github/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/github/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/github/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/github/oauth2/callback"
|
||||
),
|
||||
GitlabConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/gitlab/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/gitlab/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/gitlab/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/gitlab/create"
|
||||
),
|
||||
GitlabOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/gitlab/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/gitlab/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/gitlab/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/gitlab/oauth2/callback"
|
||||
),
|
||||
VercelOauthCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/vercel/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/vercel/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/vercel/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/vercel/oauth2/callback"
|
||||
),
|
||||
VercelConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/vercel/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/vercel/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/vercel/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/vercel/create"
|
||||
),
|
||||
FlyioConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/flyio/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/flyio/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/flyio/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/flyio/create"
|
||||
),
|
||||
HashicorpVaultConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/hashicorp-vault/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/hashicorp-vault/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/hashicorp-vault/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/hashicorp-vault/create"
|
||||
),
|
||||
HasuraCloudConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/hasura-cloud/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/hasura-cloud/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/hasura-cloud/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/hasura-cloud/create"
|
||||
),
|
||||
LaravelForgeConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/laravel-forge/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/laravel-forge/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/laravel-forge/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/laravel-forge/create"
|
||||
),
|
||||
NorthflankConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/northflank/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/northflank/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/northflank/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/northflank/create"
|
||||
),
|
||||
RailwayConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/railway/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/railway/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/railway/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/railway/create"
|
||||
),
|
||||
RenderConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/render/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/render/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/render/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/render/create"
|
||||
),
|
||||
RundeckConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/rundeck/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/rundeck/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/rundeck/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/rundeck/create"
|
||||
),
|
||||
WindmillConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/windmill/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/windmill/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/windmill/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/windmill/create"
|
||||
),
|
||||
TravisCIConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/travisci/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/travisci/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/travisci/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/travisci/create"
|
||||
),
|
||||
TerraformCloudConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/terraform-cloud/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/terraform-cloud/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/terraform-cloud/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/terraform-cloud/create"
|
||||
),
|
||||
TeamcityConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/teamcity/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/teamcity/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/teamcity/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/teamcity/create"
|
||||
),
|
||||
SupabaseConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/supabase/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/supabase/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/supabase/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/supabase/create"
|
||||
),
|
||||
OctopusDeployCloudConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/octopus-deploy/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/octopus-deploy/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/octopus-deploy/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/octopus-deploy/create"
|
||||
),
|
||||
DatabricksConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/databricks/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/databricks/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/databricks/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/databricks/create"
|
||||
),
|
||||
QoveryConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/qovery/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/qovery/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/qovery/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/qovery/create"
|
||||
),
|
||||
Cloud66ConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/cloud-66/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/cloud-66/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/cloud-66/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/cloud-66/create"
|
||||
),
|
||||
NetlifyConfigurePage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/netlify/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/netlify/create"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/netlify/create",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/netlify/create"
|
||||
),
|
||||
NetlifyOuathCallbackPage: setRoute(
|
||||
"/projects/secret-management/$projectId/integrations/netlify/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-management/$projectId/_secret-manager-layout/integrations/netlify/oauth2/callback"
|
||||
"/organizations/$orgId/projects/secret-management/$projectId/integrations/netlify/oauth2/callback",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-management/$projectId/_secret-manager-layout/integrations/netlify/oauth2/callback"
|
||||
)
|
||||
}
|
||||
},
|
||||
CertManager: {
|
||||
CertAuthDetailsByIDPage: setRoute(
|
||||
"/projects/cert-management/$projectId/ca/$caName",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/ca/$caName"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/ca/$caId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caId"
|
||||
),
|
||||
SubscribersPage: setRoute(
|
||||
"/projects/cert-management/$projectId/subscribers",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/subscribers"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/subscribers",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/subscribers"
|
||||
),
|
||||
CertificateAuthoritiesPage: setRoute(
|
||||
"/projects/cert-management/$projectId/certificate-authorities",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/certificate-authorities"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/certificate-authorities",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/certificate-authorities"
|
||||
),
|
||||
AlertingPage: setRoute(
|
||||
"/projects/cert-management/$projectId/alerting",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/alerting"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/alerting",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/alerting"
|
||||
),
|
||||
PkiCollectionDetailsByIDPage: setRoute(
|
||||
"/projects/cert-management/$projectId/pki-collections/$collectionId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/pki-collections/$collectionId"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/pki-collections/$collectionId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/pki-collections/$collectionId"
|
||||
),
|
||||
PkiSubscriberDetailsByIDPage: setRoute(
|
||||
"/projects/cert-management/$projectId/subscribers/$subscriberName",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/subscribers/$subscriberName"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/subscribers/$subscriberName",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/subscribers/$subscriberName"
|
||||
),
|
||||
IntegrationsListPage: setRoute(
|
||||
"/projects/cert-management/$projectId/integrations",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/integrations/"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/integrations",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/integrations/"
|
||||
),
|
||||
PkiSyncDetailsByIDPage: setRoute(
|
||||
"/projects/cert-management/$projectId/integrations/$syncId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/cert-management/$projectId/_cert-manager-layout/integrations/$syncId"
|
||||
"/organizations/$orgId/projects/cert-management/$projectId/integrations/$syncId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/integrations/$syncId"
|
||||
)
|
||||
},
|
||||
Ssh: {
|
||||
SshCaByIDPage: setRoute(
|
||||
"/projects/ssh/$projectId/ca/$caId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/ca/$caId"
|
||||
"/organizations/$orgId/projects/ssh/$projectId/ca/$caId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/ssh/$projectId/_ssh-layout/ca/$caId"
|
||||
),
|
||||
SshHostGroupDetailsByIDPage: setRoute(
|
||||
"/projects/ssh/$projectId/ssh-host-groups/$sshHostGroupId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/ssh/$projectId/_ssh-layout/ssh-host-groups/$sshHostGroupId"
|
||||
"/organizations/$orgId/projects/ssh/$projectId/ssh-host-groups/$sshHostGroupId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/ssh/$projectId/_ssh-layout/ssh-host-groups/$sshHostGroupId"
|
||||
)
|
||||
},
|
||||
SecretScanning: {
|
||||
DataSourceByIdPage: setRoute(
|
||||
"/projects/secret-scanning/$projectId/data-sources/$type/$dataSourceId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/data-sources/$type/$dataSourceId"
|
||||
"/organizations/$orgId/projects/secret-scanning/$projectId/data-sources/$type/$dataSourceId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-scanning/$projectId/_secret-scanning-layout/data-sources/$type/$dataSourceId"
|
||||
),
|
||||
FindingsPage: setRoute(
|
||||
"/projects/secret-scanning/$projectId/findings",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/secret-scanning/$projectId/_secret-scanning-layout/findings"
|
||||
"/organizations/$orgId/projects/secret-scanning/$projectId/findings",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/secret-scanning/$projectId/_secret-scanning-layout/findings"
|
||||
)
|
||||
},
|
||||
Pam: {
|
||||
AccountsPage: setRoute(
|
||||
"/projects/pam/$projectId/accounts",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/pam/$projectId/_pam-layout/accounts"
|
||||
"/organizations/$orgId/projects/pam/$projectId/accounts",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/accounts"
|
||||
),
|
||||
ResourcesPage: setRoute(
|
||||
"/projects/pam/$projectId/resources",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/pam/$projectId/_pam-layout/resources"
|
||||
"/organizations/$orgId/projects/pam/$projectId/resources",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/resources"
|
||||
),
|
||||
SessionsPage: setRoute(
|
||||
"/projects/pam/$projectId/sessions",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/pam/$projectId/_pam-layout/sessions/"
|
||||
"/organizations/$orgId/projects/pam/$projectId/sessions",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/"
|
||||
),
|
||||
PamSessionByIDPage: setRoute(
|
||||
"/projects/pam/$projectId/sessions/$sessionId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/projects/pam/$projectId/_pam-layout/sessions/$sessionId"
|
||||
"/organizations/$orgId/projects/pam/$projectId/sessions/$sessionId",
|
||||
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/pam/$projectId/_pam-layout/sessions/$sessionId"
|
||||
)
|
||||
},
|
||||
Public: {
|
||||
|
||||
@@ -4,6 +4,7 @@ export {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionAuditLogsActions,
|
||||
ProjectPermissionCertificateActions,
|
||||
ProjectPermissionCertificateAuthorityActions,
|
||||
ProjectPermissionCertificateProfileActions,
|
||||
ProjectPermissionCmekActions,
|
||||
ProjectPermissionDynamicSecretActions,
|
||||
@@ -12,6 +13,7 @@ export {
|
||||
ProjectPermissionKmipActions,
|
||||
ProjectPermissionMemberActions,
|
||||
ProjectPermissionPkiSubscriberActions,
|
||||
ProjectPermissionPkiSyncActions,
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSshHostActions,
|
||||
ProjectPermissionSub
|
||||
|
||||
@@ -12,7 +12,9 @@ export enum ProjectPermissionCertificateActions {
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
ReadPrivateKey = "read-private-key"
|
||||
List = "list",
|
||||
ReadPrivateKey = "read-private-key",
|
||||
Import = "import"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionSecretActions {
|
||||
@@ -67,6 +69,7 @@ export enum ProjectPermissionPkiSyncActions {
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
List = "list",
|
||||
SyncCertificates = "sync-certificates",
|
||||
ImportCertificates = "import-certificates",
|
||||
RemoveCertificates = "remove-certificates"
|
||||
@@ -128,13 +131,25 @@ export enum ProjectPermissionPkiTemplateActions {
|
||||
ListCerts = "list-certs"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionCertificateProfileActions {
|
||||
export enum ProjectPermissionCertificateAuthorityActions {
|
||||
Read = "read",
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
List = "list",
|
||||
Renew = "renew",
|
||||
SignIntermediate = "sign-intermediate"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionCertificateProfileActions {
|
||||
Read = "read",
|
||||
List = "list",
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete",
|
||||
IssueCert = "issue-cert",
|
||||
RevealAcmeEabSecret = "reveal-acme-eab-secret"
|
||||
RevealAcmeEabSecret = "reveal-acme-eab-secret",
|
||||
RotateAcmeEabSecret = "rotate-acme-eab-secret"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionSecretRotationActions {
|
||||
@@ -230,6 +245,9 @@ export type ConditionalProjectPermissionSubject =
|
||||
| ProjectPermissionSub.SshHosts
|
||||
| ProjectPermissionSub.PkiSubscribers
|
||||
| ProjectPermissionSub.CertificateTemplates
|
||||
| ProjectPermissionSub.CertificateAuthorities
|
||||
| ProjectPermissionSub.Certificates
|
||||
| ProjectPermissionSub.CertificateProfiles
|
||||
| ProjectPermissionSub.SecretFolders
|
||||
| ProjectPermissionSub.SecretImports
|
||||
| ProjectPermissionSub.SecretRotation
|
||||
@@ -361,7 +379,22 @@ export type SecretSyncSubjectFields = {
|
||||
};
|
||||
|
||||
export type PkiSyncSubjectFields = {
|
||||
subscriberId: string;
|
||||
subscriberName: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type CertificateAuthoritySubjectFields = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type CertificateSubjectFields = {
|
||||
commonName?: string;
|
||||
altNames?: string;
|
||||
serialNumber?: string;
|
||||
};
|
||||
|
||||
export type CertificateProfileSubjectFields = {
|
||||
slug: string;
|
||||
};
|
||||
|
||||
export type SecretRotationSubjectFields = {
|
||||
@@ -457,8 +490,21 @@ export type ProjectPermissionSet =
|
||||
| (ForcedSubject<ProjectPermissionSub.Identity> & IdentityManagementSubjectFields)
|
||||
)
|
||||
]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.CertificateAuthorities]
|
||||
| [ProjectPermissionCertificateActions, ProjectPermissionSub.Certificates]
|
||||
| [
|
||||
ProjectPermissionCertificateAuthorityActions,
|
||||
(
|
||||
| ProjectPermissionSub.CertificateAuthorities
|
||||
| (ForcedSubject<ProjectPermissionSub.CertificateAuthorities> &
|
||||
CertificateAuthoritySubjectFields)
|
||||
)
|
||||
]
|
||||
| [
|
||||
ProjectPermissionCertificateActions,
|
||||
(
|
||||
| ProjectPermissionSub.Certificates
|
||||
| (ForcedSubject<ProjectPermissionSub.Certificates> & CertificateSubjectFields)
|
||||
)
|
||||
]
|
||||
| [
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
(
|
||||
@@ -484,7 +530,14 @@ export type ProjectPermissionSet =
|
||||
| (ForcedSubject<ProjectPermissionSub.PkiSubscribers> & PkiSubscriberSubjectFields)
|
||||
)
|
||||
]
|
||||
| [ProjectPermissionCertificateProfileActions, ProjectPermissionSub.CertificateProfiles]
|
||||
| [
|
||||
ProjectPermissionCertificateProfileActions,
|
||||
(
|
||||
| ProjectPermissionSub.CertificateProfiles
|
||||
| (ForcedSubject<ProjectPermissionSub.CertificateProfiles> &
|
||||
CertificateProfileSubjectFields)
|
||||
)
|
||||
]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiAlerts]
|
||||
| [ProjectPermissionActions, ProjectPermissionSub.PkiCollections]
|
||||
| [ProjectPermissionActions.Delete, ProjectPermissionSub.Project]
|
||||
|
||||
@@ -15,6 +15,7 @@ export {
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionAuditLogsActions,
|
||||
ProjectPermissionCertificateActions,
|
||||
ProjectPermissionCertificateAuthorityActions,
|
||||
ProjectPermissionCertificateProfileActions,
|
||||
ProjectPermissionCmekActions,
|
||||
ProjectPermissionDynamicSecretActions,
|
||||
@@ -23,6 +24,7 @@ export {
|
||||
ProjectPermissionKmipActions,
|
||||
ProjectPermissionMemberActions,
|
||||
ProjectPermissionPkiSubscriberActions,
|
||||
ProjectPermissionPkiSyncActions,
|
||||
ProjectPermissionPkiTemplateActions,
|
||||
ProjectPermissionSshHostActions,
|
||||
ProjectPermissionSub,
|
||||
|
||||
@@ -49,6 +49,7 @@ import { BitbucketConnectionMethod } from "@app/hooks/api/appConnections/types/b
|
||||
import { ChecklyConnectionMethod } from "@app/hooks/api/appConnections/types/checkly-connection";
|
||||
import { ChefConnectionMethod } from "@app/hooks/api/appConnections/types/chef-connection";
|
||||
import { DigitalOceanConnectionMethod } from "@app/hooks/api/appConnections/types/digital-ocean";
|
||||
import { DNSMadeEasyConnectionMethod } from "@app/hooks/api/appConnections/types/dns-made-easy-connection";
|
||||
import { HerokuConnectionMethod } from "@app/hooks/api/appConnections/types/heroku-connection";
|
||||
import { LaravelForgeConnectionMethod } from "@app/hooks/api/appConnections/types/laravel-forge-connection";
|
||||
import { NetlifyConnectionMethod } from "@app/hooks/api/appConnections/types/netlify-connection";
|
||||
@@ -111,6 +112,7 @@ export const APP_CONNECTION_MAP: Record<
|
||||
[AppConnection.Flyio]: { name: "Fly.io", image: "Flyio.svg" },
|
||||
[AppConnection.GitLab]: { name: "GitLab", image: "GitLab.png" },
|
||||
[AppConnection.Cloudflare]: { name: "Cloudflare", image: "Cloudflare.png" },
|
||||
[AppConnection.DNSMadeEasy]: { name: "DNS Made Easy", image: "DNSMadeEasy.svg", size: 120 },
|
||||
[AppConnection.Zabbix]: { name: "Zabbix", image: "Zabbix.png" },
|
||||
[AppConnection.Railway]: { name: "Railway", image: "Railway.png" },
|
||||
[AppConnection.Bitbucket]: { name: "Bitbucket", image: "Bitbucket.png" },
|
||||
@@ -214,6 +216,8 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
|
||||
return { name: "Client Secret", icon: faKey };
|
||||
case AzureClientSecretsConnectionMethod.Certificate:
|
||||
return { name: "Certificate", icon: faCertificate };
|
||||
case DNSMadeEasyConnectionMethod.APIKeySecret:
|
||||
return { name: "API Key & Secret", icon: faKey };
|
||||
default:
|
||||
throw new Error(`Unhandled App Connection Method: ${method}`);
|
||||
}
|
||||
|
||||
@@ -15,10 +15,20 @@ export const PKI_SYNC_MAP: Record<
|
||||
[PkiSync.AwsCertificateManager]: {
|
||||
name: "AWS Certificate Manager",
|
||||
image: "Amazon Web Services.png"
|
||||
},
|
||||
[PkiSync.AwsSecretsManager]: {
|
||||
name: "AWS Secrets Manager",
|
||||
image: "Amazon Web Services.png"
|
||||
},
|
||||
[PkiSync.Chef]: {
|
||||
name: "Chef",
|
||||
image: "Chef.png"
|
||||
}
|
||||
};
|
||||
|
||||
export const PKI_SYNC_CONNECTION_MAP: Record<PkiSync, AppConnection> = {
|
||||
[PkiSync.AzureKeyVault]: AppConnection.AzureKeyVault,
|
||||
[PkiSync.AwsCertificateManager]: AppConnection.AWS
|
||||
[PkiSync.AwsCertificateManager]: AppConnection.AWS,
|
||||
[PkiSync.AwsSecretsManager]: AppConnection.AWS,
|
||||
[PkiSync.Chef]: AppConnection.Chef
|
||||
};
|
||||
|
||||
@@ -14,11 +14,6 @@ const secretsToBeAdded = [
|
||||
secretValue: "OVERRIDE_THIS",
|
||||
secretComment: "Override secrets with personal value"
|
||||
},
|
||||
{
|
||||
secretKey: "DB_PASSWORD",
|
||||
secretValue: "OVERRIDE_THIS",
|
||||
secretComment: "Another secret override"
|
||||
},
|
||||
{
|
||||
secretKey: "DB_PASSWORD",
|
||||
secretValue: "example_password"
|
||||
@@ -64,11 +59,11 @@ export const initProjectHelper = async ({ projectName }: { projectName: string }
|
||||
export const getProjectBaseURL = (type: ProjectType) => {
|
||||
switch (type) {
|
||||
case ProjectType.SecretManager:
|
||||
return "/projects/secret-management/$projectId";
|
||||
return "/organizations/$orgId/projects/secret-management/$projectId";
|
||||
case ProjectType.CertificateManager:
|
||||
return "/projects/cert-management/$projectId";
|
||||
return "/organizations/$orgId/projects/cert-management/$projectId";
|
||||
default:
|
||||
return `/projects/${type}/$projectId` as const;
|
||||
return `/organizations/$orgId/projects/${type}/$projectId` as const;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -77,15 +72,15 @@ export const getProjectBaseURL = (type: ProjectType) => {
|
||||
export const getProjectHomePage = (type: ProjectType, environments: ProjectEnv[]) => {
|
||||
switch (type) {
|
||||
case ProjectType.SecretManager:
|
||||
return "/projects/secret-management/$projectId/overview" as const;
|
||||
return "/organizations/$orgId/projects/secret-management/$projectId/overview" as const;
|
||||
case ProjectType.CertificateManager:
|
||||
return "/projects/cert-management/$projectId/policies" as const;
|
||||
return "/organizations/$orgId/projects/cert-management/$projectId/policies" as const;
|
||||
case ProjectType.SecretScanning:
|
||||
return `/projects/${type}/$projectId/data-sources` as const;
|
||||
return `/organizations/$orgId/projects/${type}/$projectId/data-sources` as const;
|
||||
case ProjectType.PAM:
|
||||
return `/projects/${type}/$projectId/accounts` as const;
|
||||
return `/organizations/$orgId/projects/${type}/$projectId/accounts` as const;
|
||||
default:
|
||||
return `/projects/${type}/$projectId/overview` as const;
|
||||
return `/organizations/$orgId/projects/${type}/$projectId/overview` as const;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./queries";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,37 @@
|
||||
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { appConnectionKeys } from "../queries";
|
||||
import { TDNSMadeEasyZone } from "./types";
|
||||
|
||||
const dnsMadeEasyConnectionKeys = {
|
||||
all: [...appConnectionKeys.all, "dns-made-easy"] as const,
|
||||
listZones: (connectionId: string) =>
|
||||
[...dnsMadeEasyConnectionKeys.all, "zones", connectionId] as const
|
||||
};
|
||||
|
||||
export const useDNSMadeEasyConnectionListZones = (
|
||||
connectionId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TDNSMadeEasyZone[],
|
||||
unknown,
|
||||
TDNSMadeEasyZone[],
|
||||
ReturnType<typeof dnsMadeEasyConnectionKeys.listZones>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: dnsMadeEasyConnectionKeys.listZones(connectionId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TDNSMadeEasyZone[]>(
|
||||
`/api/v1/app-connections/dns-made-easy/${connectionId}/dns-made-easy-zones`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
...options
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
export type TDNSMadeEasyZone = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
@@ -29,6 +29,7 @@ export enum AppConnection {
|
||||
Flyio = "flyio",
|
||||
GitLab = "gitlab",
|
||||
Cloudflare = "cloudflare",
|
||||
DNSMadeEasy = "dns-made-easy",
|
||||
Bitbucket = "bitbucket",
|
||||
Zabbix = "zabbix",
|
||||
Railway = "railway",
|
||||
|
||||
@@ -184,6 +184,10 @@ export type TRedisConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.Redis;
|
||||
};
|
||||
|
||||
export type TDNSMadeEasyConnectionOption = TAppConnectionOptionBase & {
|
||||
app: AppConnection.DNSMadeEasy;
|
||||
};
|
||||
|
||||
export type TAppConnectionOption =
|
||||
| TAwsConnectionOption
|
||||
| TGitHubConnectionOption
|
||||
@@ -225,7 +229,8 @@ export type TAppConnectionOption =
|
||||
| TOktaConnectionOption
|
||||
| TAzureAdCsConnectionOption
|
||||
| TLaravelForgeConnectionOption
|
||||
| TChefConnectionOption;
|
||||
| TChefConnectionOption
|
||||
| TDNSMadeEasyConnectionOption;
|
||||
|
||||
export type TAppConnectionOptionMap = {
|
||||
[AppConnection.AWS]: TAwsConnectionOption;
|
||||
@@ -257,6 +262,7 @@ export type TAppConnectionOptionMap = {
|
||||
[AppConnection.Flyio]: TFlyioConnectionOption;
|
||||
[AppConnection.GitLab]: TGitlabConnectionOption;
|
||||
[AppConnection.Cloudflare]: TCloudflareConnectionOption;
|
||||
[AppConnection.DNSMadeEasy]: TDNSMadeEasyConnectionOption;
|
||||
[AppConnection.Bitbucket]: TBitbucketConnectionOption;
|
||||
[AppConnection.Zabbix]: TZabbixConnectionOption;
|
||||
[AppConnection.Railway]: TRailwayConnectionOption;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
|
||||
|
||||
export enum DNSMadeEasyConnectionMethod {
|
||||
APIKeySecret = "api-key-secret"
|
||||
}
|
||||
|
||||
export type TDNSMadeEasyConnection = TRootAppConnection & { app: AppConnection.DNSMadeEasy } & {
|
||||
method: DNSMadeEasyConnectionMethod.APIKeySecret;
|
||||
credentials: {
|
||||
apiKey: string;
|
||||
secretKey: string;
|
||||
};
|
||||
};
|
||||
@@ -15,6 +15,7 @@ import { TChefConnection } from "./chef-connection";
|
||||
import { TCloudflareConnection } from "./cloudflare-connection";
|
||||
import { TDatabricksConnection } from "./databricks-connection";
|
||||
import { TDigitalOceanConnection } from "./digital-ocean";
|
||||
import { TDNSMadeEasyConnection } from "./dns-made-easy-connection";
|
||||
import { TFlyioConnection } from "./flyio-connection";
|
||||
import { TGcpConnection } from "./gcp-connection";
|
||||
import { TGitHubConnection } from "./github-connection";
|
||||
@@ -57,6 +58,7 @@ export * from "./checkly-connection";
|
||||
export * from "./chef-connection";
|
||||
export * from "./cloudflare-connection";
|
||||
export * from "./databricks-connection";
|
||||
export * from "./dns-made-easy-connection";
|
||||
export * from "./flyio-connection";
|
||||
export * from "./gcp-connection";
|
||||
export * from "./github-connection";
|
||||
@@ -127,7 +129,8 @@ export type TAppConnection =
|
||||
| TNorthflankConnection
|
||||
| TOktaConnection
|
||||
| TRedisConnection
|
||||
| TChefConnection;
|
||||
| TChefConnection
|
||||
| TDNSMadeEasyConnection;
|
||||
|
||||
export type TAvailableAppConnection = Pick<TAppConnection, "name" | "id" | "projectId">;
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[EventType.SIGN_INTERMEDIATE]: "Sign intermediate",
|
||||
[EventType.IMPORT_CA_CERT]: "Import CA certificate",
|
||||
[EventType.GET_CA_CRL]: "Get CA CRL",
|
||||
[EventType.ISSUE_CERT]: "Issue certificate",
|
||||
[EventType.ISSUE_CERT]: "Request certificate",
|
||||
[EventType.IMPORT_CERT]: "Import certificate",
|
||||
[EventType.GET_CERT]: "Get certificate",
|
||||
[EventType.DELETE_CERT]: "Delete certificate",
|
||||
@@ -225,7 +225,7 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[EventType.UPDATE_PKI_SUBSCRIBER]: "Update PKI subscriber",
|
||||
[EventType.DELETE_PKI_SUBSCRIBER]: "Delete PKI subscriber",
|
||||
[EventType.GET_PKI_SUBSCRIBER]: "Get PKI subscriber",
|
||||
[EventType.ISSUE_PKI_SUBSCRIBER_CERT]: "Issue PKI subscriber certificate",
|
||||
[EventType.ISSUE_PKI_SUBSCRIBER_CERT]: "Request PKI subscriber certificate",
|
||||
[EventType.SIGN_PKI_SUBSCRIBER_CERT]: "Sign PKI subscriber certificate",
|
||||
[EventType.AUTOMATED_RENEW_SUBSCRIBER_CERT]: "Automated renew PKI subscriber certificate",
|
||||
[EventType.LIST_PKI_SUBSCRIBER_CERTS]: "List PKI subscriber certificates",
|
||||
@@ -262,31 +262,32 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[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",
|
||||
[EventType.PAM_SESSION_GET]: "PAM Session Get",
|
||||
[EventType.PAM_SESSION_LIST]: "PAM Session List",
|
||||
[EventType.PAM_FOLDER_CREATE]: "PAM Folder Create",
|
||||
[EventType.PAM_FOLDER_UPDATE]: "PAM Folder Update",
|
||||
[EventType.PAM_FOLDER_DELETE]: "PAM Folder Delete",
|
||||
[EventType.PAM_ACCOUNT_LIST]: "PAM Account List",
|
||||
[EventType.PAM_ACCOUNT_ACCESS]: "PAM Account Access",
|
||||
[EventType.PAM_ACCOUNT_CREATE]: "PAM Account Create",
|
||||
[EventType.PAM_ACCOUNT_UPDATE]: "PAM Account Update",
|
||||
[EventType.PAM_ACCOUNT_DELETE]: "PAM Account Delete",
|
||||
[EventType.PAM_RESOURCE_LIST]: "PAM Resource List",
|
||||
[EventType.PAM_RESOURCE_GET]: "PAM Resource Get",
|
||||
[EventType.PAM_RESOURCE_CREATE]: "PAM Resource Create",
|
||||
[EventType.PAM_RESOURCE_UPDATE]: "PAM Resource Update",
|
||||
[EventType.PAM_RESOURCE_DELETE]: "PAM Resource Delete",
|
||||
[EventType.PAM_SESSION_CREDENTIALS_GET]: "Get PAM Session Credentials",
|
||||
[EventType.PAM_SESSION_START]: "Start PAM Session",
|
||||
[EventType.PAM_SESSION_LOGS_UPDATE]: "Update PAM Session Logs",
|
||||
[EventType.PAM_SESSION_END]: "End PAM Session",
|
||||
[EventType.PAM_SESSION_GET]: "Get PAM Session",
|
||||
[EventType.PAM_SESSION_LIST]: "List PAM Sessions",
|
||||
[EventType.PAM_FOLDER_CREATE]: "Create PAM Folder",
|
||||
[EventType.PAM_FOLDER_UPDATE]: "Update PAM Folder",
|
||||
[EventType.PAM_FOLDER_DELETE]: "Delete PAM Folder",
|
||||
[EventType.PAM_ACCOUNT_LIST]: "List PAM Accounts",
|
||||
[EventType.PAM_ACCOUNT_ACCESS]: "Access PAM Account",
|
||||
[EventType.PAM_ACCOUNT_CREATE]: "Create PAM Account",
|
||||
[EventType.PAM_ACCOUNT_UPDATE]: "Update PAM Account",
|
||||
[EventType.PAM_ACCOUNT_DELETE]: "Delete PAM Account",
|
||||
[EventType.PAM_RESOURCE_LIST]: "List PAM Resources",
|
||||
[EventType.PAM_RESOURCE_GET]: "Get PAM Resource",
|
||||
[EventType.PAM_RESOURCE_CREATE]: "Create PAM Resource",
|
||||
[EventType.PAM_RESOURCE_UPDATE]: "Update PAM Resource",
|
||||
[EventType.PAM_RESOURCE_DELETE]: "Delete PAM Resource",
|
||||
|
||||
[EventType.CREATE_CERTIFICATE_PROFILE]: "Create Certificate Profile",
|
||||
[EventType.UPDATE_CERTIFICATE_PROFILE]: "Update Certificate Profile",
|
||||
[EventType.DELETE_CERTIFICATE_PROFILE]: "Delete Certificate Profile",
|
||||
[EventType.GET_CERTIFICATE_PROFILE]: "Get Certificate Profile",
|
||||
[EventType.LIST_CERTIFICATE_PROFILES]: "List Certificate Profiles",
|
||||
[EventType.ISSUE_CERTIFICATE_FROM_PROFILE]: "Issue Certificate From Profile",
|
||||
[EventType.ISSUE_CERTIFICATE_FROM_PROFILE]: "Request Certificate From Profile",
|
||||
[EventType.SIGN_CERTIFICATE_FROM_PROFILE]: "Sign Certificate From Profile",
|
||||
[EventType.ORDER_CERTIFICATE_FROM_PROFILE]: "Order Certificate From Profile",
|
||||
[EventType.GET_CERTIFICATE_PROFILE_LATEST_ACTIVE_BUNDLE]:
|
||||
@@ -314,6 +315,7 @@ const sharedProjectEvents = [
|
||||
export const projectToEventsMap: Partial<Record<ProjectType, EventType[]>> = {
|
||||
[ProjectType.PAM]: [
|
||||
...sharedProjectEvents,
|
||||
EventType.PAM_SESSION_CREDENTIALS_GET,
|
||||
EventType.PAM_SESSION_START,
|
||||
EventType.PAM_SESSION_LOGS_UPDATE,
|
||||
EventType.PAM_SESSION_END,
|
||||
|
||||
@@ -254,6 +254,7 @@ export enum EventType {
|
||||
UPDATE_IDENTITY_PROJECT_MEMBERSHIP = "update-identity-project-membership",
|
||||
DELETE_IDENTITY_PROJECT_MEMBERSHIP = "delete-identity-project-membership",
|
||||
|
||||
PAM_SESSION_CREDENTIALS_GET = "pam-session-credentials-get",
|
||||
PAM_SESSION_START = "pam-session-start",
|
||||
PAM_SESSION_LOGS_UPDATE = "pam-session-logs-update",
|
||||
PAM_SESSION_END = "pam-session-end",
|
||||
|
||||
@@ -16,12 +16,14 @@ export const caStatusToNameMap: { [K in CaStatus]: string } = {
|
||||
|
||||
export const ACME_DNS_PROVIDER_NAME_MAP: Record<AcmeDnsProvider, string> = {
|
||||
[AcmeDnsProvider.ROUTE53]: "Route53",
|
||||
[AcmeDnsProvider.Cloudflare]: "Cloudflare"
|
||||
[AcmeDnsProvider.Cloudflare]: "Cloudflare",
|
||||
[AcmeDnsProvider.DNSMadeEasy]: "DNS Made Easy"
|
||||
};
|
||||
|
||||
export const ACME_DNS_PROVIDER_APP_CONNECTION_MAP: Record<AcmeDnsProvider, AppConnection> = {
|
||||
[AcmeDnsProvider.ROUTE53]: AppConnection.AWS,
|
||||
[AcmeDnsProvider.Cloudflare]: AppConnection.Cloudflare
|
||||
[AcmeDnsProvider.Cloudflare]: AppConnection.Cloudflare,
|
||||
[AcmeDnsProvider.DNSMadeEasy]: AppConnection.DNSMadeEasy
|
||||
};
|
||||
|
||||
export const CA_TYPE_CAPABILITIES_MAP: Record<CaType, CaCapability[]> = {
|
||||
|
||||
@@ -21,7 +21,8 @@ export enum CaRenewalType {
|
||||
|
||||
export enum AcmeDnsProvider {
|
||||
ROUTE53 = "route53",
|
||||
Cloudflare = "cloudflare"
|
||||
Cloudflare = "cloudflare",
|
||||
DNSMadeEasy = "dns-made-easy"
|
||||
}
|
||||
|
||||
export enum CaCapability {
|
||||
|
||||
@@ -13,12 +13,12 @@ export {
|
||||
export {
|
||||
useGetAzureAdcsTemplates,
|
||||
useGetCa,
|
||||
useGetCaById,
|
||||
useGetCaCert,
|
||||
useGetCaCerts,
|
||||
useGetCaCertTemplates,
|
||||
useGetCaCrls,
|
||||
useGetCaCsr,
|
||||
useGetInternalCaById,
|
||||
useListCasByProjectId,
|
||||
useListCasByTypeAndProjectId,
|
||||
useListExternalCasByProjectId
|
||||
|
||||
@@ -27,21 +27,20 @@ import {
|
||||
export const useUpdateCa = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TUnifiedCertificateAuthority, object, TUpdateCertificateAuthorityDTO>({
|
||||
mutationFn: async ({ caName, ...body }) => {
|
||||
mutationFn: async ({ id, ...body }) => {
|
||||
const { data } = await apiRequest.patch<TUnifiedCertificateAuthority>(
|
||||
`/api/v1/pki/ca/${body.type}/${caName}`,
|
||||
`/api/v1/cert-manager/ca/${body.type}/${id}`,
|
||||
body
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess: ({ projectId, type }, { caName }) => {
|
||||
caKeys.getCaByNameAndProjectId(caName, projectId);
|
||||
onSuccess: ({ projectId, type }, { id }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: caKeys.listCasByTypeAndProjectId(type, projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: caKeys.getCaByNameAndProjectId(caName, projectId)
|
||||
queryKey: caKeys.getCaById(id)
|
||||
});
|
||||
// Invalidate external CAs list
|
||||
queryClient.invalidateQueries({
|
||||
@@ -56,7 +55,7 @@ export const useCreateCa = () => {
|
||||
return useMutation<TUnifiedCertificateAuthority, object, TCreateCertificateAuthorityDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { data } = await apiRequest.post<TUnifiedCertificateAuthority>(
|
||||
`/api/v1/pki/ca/${body.type}`,
|
||||
`/api/v1/cert-manager/ca/${body.type}`,
|
||||
body
|
||||
);
|
||||
return data;
|
||||
@@ -76,14 +75,9 @@ export const useCreateCa = () => {
|
||||
export const useDeleteCa = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TUnifiedCertificateAuthority, object, TDeleteCertificateAuthorityDTO>({
|
||||
mutationFn: async ({ caName, type, projectId }) => {
|
||||
mutationFn: async ({ id, type }) => {
|
||||
const { data } = await apiRequest.delete<TUnifiedCertificateAuthority>(
|
||||
`/api/v1/pki/ca/${type}/${caName}`,
|
||||
{
|
||||
data: {
|
||||
projectId
|
||||
}
|
||||
}
|
||||
`/api/v1/cert-manager/ca/${type}/${id}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
@@ -104,7 +98,7 @@ export const useSignIntermediate = () => {
|
||||
return useMutation<TSignIntermediateResponse, object, TSignIntermediateDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { data } = await apiRequest.post<TSignIntermediateResponse>(
|
||||
`/api/v1/pki/ca/${body.caId}/sign-intermediate`,
|
||||
`/api/v1/cert-manager/ca/internal/${body.caId}/sign-intermediate`,
|
||||
body
|
||||
);
|
||||
return data;
|
||||
@@ -117,13 +111,14 @@ export const useImportCaCertificate = (projectId: string) => {
|
||||
return useMutation<TImportCaCertificateResponse, object, TImportCaCertificateDTO>({
|
||||
mutationFn: async ({ caId, ...body }) => {
|
||||
const { data } = await apiRequest.post<TImportCaCertificateResponse>(
|
||||
`/api/v1/pki/ca/${caId}/import-certificate`,
|
||||
`/api/v1/cert-manager/ca/internal/${caId}/import-certificate`,
|
||||
body
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { caId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: projectKeys.getProjectCas({ projectId }) });
|
||||
queryClient.invalidateQueries({ queryKey: caKeys.getCaById(caId) });
|
||||
queryClient.invalidateQueries({ queryKey: caKeys.getCaCerts(caId) });
|
||||
queryClient.invalidateQueries({ queryKey: caKeys.getCaCert(caId) });
|
||||
queryClient.invalidateQueries({
|
||||
@@ -133,7 +128,7 @@ export const useImportCaCertificate = (projectId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// consider rename to issue certificate
|
||||
// TODO: DEPRECATE
|
||||
export const useCreateCertificate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCreateCertificateResponse, object, TCreateCertificateDTO>({
|
||||
@@ -157,7 +152,7 @@ export const useCreateCertificateV3 = (options?: { projectId?: string }) => {
|
||||
return useMutation<TCreateCertificateV3Response, object, TCreateCertificateV3DTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { data } = await apiRequest.post<TCreateCertificateV3Response>(
|
||||
"/api/v3/pki/certificates/issue-certificate",
|
||||
"/api/v1/cert-manager/certificates/issue-certificate",
|
||||
body
|
||||
);
|
||||
return data;
|
||||
@@ -185,7 +180,7 @@ export const useOrderCertificateWithProfile = () => {
|
||||
return useMutation<TOrderCertificateResponse, object, TOrderCertificateDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { data } = await apiRequest.post<TOrderCertificateResponse>(
|
||||
"/api/v3/pki/certificates/order-certificate",
|
||||
"/api/v1/cert-manager/certificates/order-certificate",
|
||||
body
|
||||
);
|
||||
return data;
|
||||
@@ -203,7 +198,7 @@ export const useRenewCa = () => {
|
||||
return useMutation<TRenewCaResponse, object, TRenewCaDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { data } = await apiRequest.post<TRenewCaResponse>(
|
||||
`/api/v1/pki/ca/${body.caId}/renew`,
|
||||
`/api/v1/cert-manager/ca/internal/${body.caId}/renew`,
|
||||
body
|
||||
);
|
||||
return data;
|
||||
|
||||
@@ -4,7 +4,11 @@ import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TCertificateTemplate } from "../certificateTemplates/types";
|
||||
import { CaType } from "./enums";
|
||||
import { TAzureAdCsTemplate, TCertificateAuthority, TUnifiedCertificateAuthority } from "./types";
|
||||
import {
|
||||
TAzureAdCsTemplate,
|
||||
TInternalCertificateAuthority,
|
||||
TUnifiedCertificateAuthority
|
||||
} from "./types";
|
||||
|
||||
export const caKeys = {
|
||||
getCaById: (caId: string) => [{ caId }, "ca"],
|
||||
@@ -25,24 +29,16 @@ export const caKeys = {
|
||||
]
|
||||
};
|
||||
|
||||
export const useGetCa = ({
|
||||
caName,
|
||||
projectId,
|
||||
type
|
||||
}: {
|
||||
caName: string;
|
||||
projectId: string;
|
||||
type: CaType;
|
||||
}) => {
|
||||
export const useGetCa = ({ caId, type }: { caId: string; type: CaType }) => {
|
||||
return useQuery({
|
||||
queryKey: caKeys.getCaByNameAndProjectId(caName, projectId),
|
||||
queryKey: caKeys.getCaById(caId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TUnifiedCertificateAuthority>(
|
||||
`/api/v1/pki/ca/${type}/${caName}?projectId=${projectId}`
|
||||
`/api/v1/cert-manager/ca/${type}/${caId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caName && projectId && type)
|
||||
enabled: Boolean(caId && type)
|
||||
});
|
||||
};
|
||||
|
||||
@@ -51,7 +47,7 @@ export const useListCasByTypeAndProjectId = (type: CaType, projectId: string) =>
|
||||
queryKey: caKeys.listCasByTypeAndProjectId(type, projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TUnifiedCertificateAuthority[]>(
|
||||
`/api/v1/pki/ca/${type}?projectId=${projectId}`
|
||||
`/api/v1/cert-manager/ca/${type}?projectId=${projectId}`
|
||||
);
|
||||
|
||||
return data;
|
||||
@@ -65,7 +61,7 @@ export const useListCasByProjectId = (projectId: string) => {
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateAuthorities: TUnifiedCertificateAuthority[];
|
||||
}>(`/api/v2/pki/ca?projectId=${projectId}`);
|
||||
}>(`/api/v1/cert-manager/ca?projectId=${projectId}`);
|
||||
|
||||
return data.certificateAuthorities;
|
||||
}
|
||||
@@ -78,10 +74,10 @@ export const useListExternalCasByProjectId = (projectId: string) => {
|
||||
queryFn: async () => {
|
||||
const [acmeResponse, azureAdCsResponse] = await Promise.allSettled([
|
||||
apiRequest.get<TUnifiedCertificateAuthority[]>(
|
||||
`/api/v1/pki/ca/${CaType.ACME}?projectId=${projectId}`
|
||||
`/api/v1/cert-manager/ca/${CaType.ACME}?projectId=${projectId}`
|
||||
),
|
||||
apiRequest.get<TUnifiedCertificateAuthority[]>(
|
||||
`/api/v1/pki/ca/${CaType.AZURE_AD_CS}?projectId=${projectId}`
|
||||
`/api/v1/cert-manager/ca/${CaType.AZURE_AD_CS}?projectId=${projectId}`
|
||||
)
|
||||
]);
|
||||
|
||||
@@ -100,14 +96,14 @@ export const useListExternalCasByProjectId = (projectId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetCaById = (caId: string) => {
|
||||
export const useGetInternalCaById = (caId: string) => {
|
||||
return useQuery({
|
||||
queryKey: caKeys.getCaById(caId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { ca }
|
||||
} = await apiRequest.get<{ ca: TCertificateAuthority }>(`/api/v1/pki/ca/${caId}`);
|
||||
return ca;
|
||||
const { data } = await apiRequest.get<TInternalCertificateAuthority>(
|
||||
`/api/v1/cert-manager/ca/internal/${caId}`
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caId)
|
||||
});
|
||||
@@ -124,7 +120,7 @@ export const useGetCaCerts = (caId: string) => {
|
||||
serialNumber: string;
|
||||
version: number;
|
||||
}[]
|
||||
>(`/api/v1/pki/ca/${caId}/ca-certificates`); // TODO: consider updating endpoint structure
|
||||
>(`/api/v1/cert-manager/ca/internal/${caId}/ca-certificates`);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caId)
|
||||
@@ -139,7 +135,7 @@ export const useGetCaCert = (caId: string) => {
|
||||
certificate: string;
|
||||
certificateChain: string;
|
||||
serialNumber: string;
|
||||
}>(`/api/v1/pki/ca/${caId}/certificate`); // TODO: consider updating endpoint structure
|
||||
}>(`/api/v1/cert-manager/ca/internal/${caId}/certificate`);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caId)
|
||||
@@ -154,7 +150,7 @@ export const useGetCaCsr = (caId: string) => {
|
||||
data: { csr }
|
||||
} = await apiRequest.get<{
|
||||
csr: string;
|
||||
}>(`/api/v1/pki/ca/${caId}/csr`);
|
||||
}>(`/api/v1/cert-manager/ca/internal/${caId}/csr`);
|
||||
return csr;
|
||||
},
|
||||
enabled: Boolean(caId)
|
||||
@@ -170,13 +166,14 @@ export const useGetCaCrls = (caId: string) => {
|
||||
id: string;
|
||||
crl: string;
|
||||
}[]
|
||||
>(`/api/v1/pki/ca/${caId}/crls`);
|
||||
>(`/api/v1/cert-manager/ca/internal/${caId}/crls`);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caId)
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useGetCaCertTemplates = (caId: string) => {
|
||||
return useQuery({
|
||||
queryKey: caKeys.getCaCertTemplates(caId),
|
||||
@@ -192,19 +189,21 @@ export const useGetCaCertTemplates = (caId: string) => {
|
||||
|
||||
export const useGetAzureAdcsTemplates = ({
|
||||
caId,
|
||||
projectId
|
||||
projectId,
|
||||
isAzureAdcsCa
|
||||
}: {
|
||||
caId: string;
|
||||
projectId: string;
|
||||
isAzureAdcsCa: boolean;
|
||||
}) => {
|
||||
return useQuery({
|
||||
queryKey: caKeys.getAzureAdcsTemplates(caId, projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
templates: TAzureAdCsTemplate[];
|
||||
}>(`/api/v1/pki/ca/azure-ad-cs/${caId}/templates?projectId=${projectId}`);
|
||||
}>(`/api/v1/cert-manager/ca/azure-ad-cs/${caId}/templates?projectId=${projectId}`);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(caId && projectId)
|
||||
enabled: Boolean(caId && projectId && isAzureAdcsCa)
|
||||
});
|
||||
};
|
||||
|
||||
@@ -66,17 +66,19 @@ export type TUnifiedCertificateAuthority =
|
||||
| TAzureAdCsCertificateAuthority
|
||||
| TInternalCertificateAuthority;
|
||||
|
||||
export type TCreateCertificateAuthorityDTO = Omit<TUnifiedCertificateAuthority, "id">;
|
||||
export type TCreateCertificateAuthorityDTO = Omit<
|
||||
TUnifiedCertificateAuthority,
|
||||
"id" | "enableDirectIssuance"
|
||||
>;
|
||||
export type TUpdateCertificateAuthorityDTO = Partial<TUnifiedCertificateAuthority> & {
|
||||
caName: string;
|
||||
projectId: string;
|
||||
id: string;
|
||||
type: CaType;
|
||||
};
|
||||
|
||||
export type TDeleteCertificateAuthorityDTO = {
|
||||
caName: string;
|
||||
type: CaType;
|
||||
id: string;
|
||||
projectId: string;
|
||||
type: CaType;
|
||||
};
|
||||
|
||||
export type TCertificateAuthority = {
|
||||
|
||||
@@ -10,4 +10,4 @@ export {
|
||||
useGetProfileCertificates,
|
||||
useListCertificateProfiles
|
||||
} from "./queries";
|
||||
export type * from "./types";
|
||||
export * from "./types";
|
||||
|
||||
@@ -17,7 +17,7 @@ export const useCreateCertificateProfile = () => {
|
||||
mutationFn: async (data) => {
|
||||
const { data: response } = await apiRequest.post<{
|
||||
certificateProfile: TCertificateProfile;
|
||||
}>("/api/v1/pki/certificate-profiles", data);
|
||||
}>("/api/v1/cert-manager/certificate-profiles", data);
|
||||
return response.certificateProfile;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
@@ -35,7 +35,7 @@ export const useUpdateCertificateProfile = () => {
|
||||
mutationFn: async ({ profileId, ...data }) => {
|
||||
const { data: response } = await apiRequest.patch<{
|
||||
certificateProfile: TCertificateProfile;
|
||||
}>(`/api/v1/pki/certificate-profiles/${profileId}`, data);
|
||||
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}`, data);
|
||||
return response.certificateProfile;
|
||||
},
|
||||
onSuccess: (profile, { profileId }) => {
|
||||
@@ -56,7 +56,7 @@ export const useDeleteCertificateProfile = () => {
|
||||
mutationFn: async ({ profileId }) => {
|
||||
const { data: response } = await apiRequest.delete<{
|
||||
certificateProfile: TCertificateProfile;
|
||||
}>(`/api/v1/pki/certificate-profiles/${profileId}`);
|
||||
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}`);
|
||||
return response.certificateProfile;
|
||||
},
|
||||
onSuccess: (profile, { profileId }) => {
|
||||
|
||||
@@ -71,7 +71,7 @@ export const useListCertificateProfiles = ({
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateProfiles: TCertificateProfile[];
|
||||
totalCount: number;
|
||||
}>("/api/v1/pki/certificate-profiles", {
|
||||
}>("/api/v1/cert-manager/certificate-profiles", {
|
||||
params: {
|
||||
projectId,
|
||||
limit,
|
||||
@@ -93,7 +93,7 @@ export const useGetCertificateProfileById = ({ profileId }: TGetCertificateProfi
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateProfile: TCertificateProfileWithDetails;
|
||||
}>(`/api/v1/pki/certificate-profiles/${profileId}`);
|
||||
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}`);
|
||||
return data.certificateProfile;
|
||||
},
|
||||
enabled: Boolean(profileId)
|
||||
@@ -109,7 +109,7 @@ export const useGetCertificateProfileBySlug = ({
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateProfile: TCertificateProfile;
|
||||
}>(`/api/v1/pki/certificate-profiles/slug/${slug}`, {
|
||||
}>(`/api/v1/cert-manager/certificate-profiles/slug/${slug}`, {
|
||||
params: { projectId }
|
||||
});
|
||||
return data.certificateProfile;
|
||||
@@ -125,7 +125,7 @@ export const useRevealAcmeEabSecret = ({ profileId }: TRevealAcmeEabSecretDTO) =
|
||||
const { data } = await apiRequest.get<{
|
||||
eabKid: string;
|
||||
eabSecret: string;
|
||||
}>(`/api/v1/pki/certificate-profiles/${profileId}/acme/eab-secret/reveal`);
|
||||
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}/acme/eab-secret/reveal`);
|
||||
return data;
|
||||
},
|
||||
enabled: Boolean(profileId)
|
||||
@@ -144,7 +144,7 @@ export const useGetProfileCertificates = ({
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificates: TProfileCertificate[];
|
||||
}>(`/api/v1/pki/certificate-profiles/${profileId}/certificates`, {
|
||||
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}/certificates`, {
|
||||
params: {
|
||||
offset,
|
||||
limit,
|
||||
|
||||
@@ -1,23 +1,46 @@
|
||||
export enum EnrollmentType {
|
||||
API = "api",
|
||||
EST = "est",
|
||||
ACME = "acme"
|
||||
}
|
||||
|
||||
export enum IssuerType {
|
||||
CA = "ca",
|
||||
SELF_SIGNED = "self-signed"
|
||||
}
|
||||
|
||||
export type TCertificateProfile = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
caId: string;
|
||||
caId: string | null;
|
||||
certificateTemplateId: string;
|
||||
slug: string;
|
||||
description?: string;
|
||||
enrollmentType: "api" | "est" | "acme";
|
||||
enrollmentType: EnrollmentType;
|
||||
issuerType: IssuerType;
|
||||
estConfigId?: string;
|
||||
apiConfigId?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
externalConfigs?: Record<string, unknown> | null;
|
||||
certificateAuthority?: {
|
||||
id: string;
|
||||
projectId?: string;
|
||||
status: string;
|
||||
name: string;
|
||||
isExternal?: boolean;
|
||||
externalType?: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type TCertificateProfileWithDetails = TCertificateProfile & {
|
||||
certificateAuthority?: {
|
||||
id: string;
|
||||
projectId: string;
|
||||
projectId?: string;
|
||||
status: string;
|
||||
name: string;
|
||||
isExternal?: boolean;
|
||||
externalType?: string | null;
|
||||
};
|
||||
certificateTemplate?: {
|
||||
id: string;
|
||||
@@ -44,11 +67,12 @@ export type TCertificateProfileWithDetails = TCertificateProfile & {
|
||||
|
||||
export type TCreateCertificateProfileDTO = {
|
||||
projectId: string;
|
||||
caId: string;
|
||||
caId?: string;
|
||||
certificateTemplateId: string;
|
||||
slug: string;
|
||||
description?: string;
|
||||
enrollmentType: "api" | "est" | "acme";
|
||||
enrollmentType: EnrollmentType;
|
||||
issuerType: IssuerType;
|
||||
estConfig?: {
|
||||
disableBootstrapCaValidation?: boolean;
|
||||
passphrase: string;
|
||||
@@ -59,12 +83,15 @@ export type TCreateCertificateProfileDTO = {
|
||||
renewBeforeDays?: number;
|
||||
};
|
||||
acmeConfig?: unknown;
|
||||
externalConfigs?: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
export type TUpdateCertificateProfileDTO = {
|
||||
profileId: string;
|
||||
slug?: string;
|
||||
description?: string;
|
||||
enrollmentType?: EnrollmentType;
|
||||
issuerType?: IssuerType;
|
||||
estConfig?: {
|
||||
disableBootstrapCaValidation?: boolean;
|
||||
passphrase?: string;
|
||||
@@ -75,6 +102,7 @@ export type TUpdateCertificateProfileDTO = {
|
||||
renewBeforeDays?: number;
|
||||
};
|
||||
acmeConfig?: unknown;
|
||||
externalConfigs?: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
export type TDeleteCertificateProfileDTO = {
|
||||
@@ -87,7 +115,9 @@ export type TListCertificateProfilesDTO = {
|
||||
offset?: number;
|
||||
search?: string;
|
||||
includeConfigs?: boolean;
|
||||
enrollmentType?: "api" | "est" | "acme";
|
||||
enrollmentType?: EnrollmentType;
|
||||
issuerType?: IssuerType;
|
||||
caId?: string;
|
||||
};
|
||||
|
||||
export type TGetCertificateProfileByIdDTO = {
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
TUpdateEstConfigDTO
|
||||
} from "./types";
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useCreateCertTemplate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateTemplate, object, TCreateCertificateTemplateDTO>({
|
||||
@@ -40,6 +41,7 @@ export const useCreateCertTemplate = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useUpdateCertTemplate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateTemplate, object, TUpdateCertificateTemplateDTO>({
|
||||
@@ -61,6 +63,7 @@ export const useUpdateCertTemplate = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useDeleteCertTemplate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificateTemplate, object, TDeleteCertificateTemplateDTO>({
|
||||
@@ -147,6 +150,7 @@ export const useDeleteCertTemplateV2 = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useCreateEstConfig = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<object, object, TCreateEstConfigDTO>({
|
||||
@@ -165,6 +169,7 @@ export const useCreateEstConfig = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useUpdateEstConfig = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<object, object, TUpdateEstConfigDTO>({
|
||||
@@ -193,7 +198,7 @@ export const useCreateCertificateTemplateV2WithPolicies = () => {
|
||||
mutationFn: async (data) => {
|
||||
const { data: response } = await apiRequest.post<{
|
||||
certificateTemplate: TCertificateTemplateV2WithPolicies;
|
||||
}>("/api/v2/certificate-templates", data);
|
||||
}>("/api/v1/cert-manager/certificate-templates", data);
|
||||
return response.certificateTemplate;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
@@ -214,7 +219,7 @@ export const useUpdateCertificateTemplateV2WithPolicies = () => {
|
||||
mutationFn: async ({ templateId, ...data }) => {
|
||||
const { data: response } = await apiRequest.patch<{
|
||||
certificateTemplate: TCertificateTemplateV2WithPolicies;
|
||||
}>(`/api/v2/certificate-templates/${templateId}`, data);
|
||||
}>(`/api/v1/cert-manager/certificate-templates/${templateId}`, data);
|
||||
return response.certificateTemplate;
|
||||
},
|
||||
onSuccess: (template, { templateId }) => {
|
||||
@@ -238,7 +243,7 @@ export const useDeleteCertificateTemplateV2WithPolicies = () => {
|
||||
mutationFn: async ({ templateId }) => {
|
||||
const { data: response } = await apiRequest.delete<{
|
||||
certificateTemplate: TCertificateTemplateV2WithPolicies;
|
||||
}>(`/api/v2/certificate-templates/${templateId}`);
|
||||
}>(`/api/v1/cert-manager/certificate-templates/${templateId}`);
|
||||
return response.certificateTemplate;
|
||||
},
|
||||
onSuccess: (template, { templateId }) => {
|
||||
|
||||
@@ -31,6 +31,7 @@ export const certTemplateKeys = {
|
||||
getTemplateV2ById: (id: string) => ["cert-template-v2", id]
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useGetCertTemplate = (id: string) => {
|
||||
return useQuery({
|
||||
queryKey: certTemplateKeys.getCertTemplateById(id),
|
||||
@@ -44,6 +45,7 @@ export const useGetCertTemplate = (id: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useListCertificateTemplates = ({
|
||||
limit = 100,
|
||||
offset = 0,
|
||||
@@ -67,6 +69,7 @@ export const useListCertificateTemplates = ({
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useGetEstConfig = (certificateTemplateId: string) => {
|
||||
return useQuery({
|
||||
queryKey: certTemplateKeys.getEstConfig(certificateTemplateId),
|
||||
@@ -92,7 +95,7 @@ export const useListCertificateTemplatesV2 = ({
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateTemplates: TCertificateTemplateV2WithPolicies[];
|
||||
totalCount: number;
|
||||
}>("/api/v2/certificate-templates", {
|
||||
}>("/api/v1/cert-manager/certificate-templates", {
|
||||
params: {
|
||||
projectId,
|
||||
limit,
|
||||
@@ -113,7 +116,7 @@ export const useGetCertificateTemplateV2ById = ({
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
certificateTemplate: TCertificateTemplateV2WithPolicies;
|
||||
}>(`/api/v2/certificate-templates/${templateId}`);
|
||||
}>(`/api/v1/cert-manager/certificate-templates/${templateId}`);
|
||||
return data.certificateTemplate;
|
||||
},
|
||||
enabled: Boolean(templateId)
|
||||
|
||||
@@ -13,23 +13,34 @@ import {
|
||||
TRenewCertificateDTO,
|
||||
TRenewCertificateResponse,
|
||||
TRevokeCertDTO,
|
||||
TUnifiedCertificateIssuanceDTO,
|
||||
TUnifiedCertificateIssuanceResponse,
|
||||
TUpdateRenewalConfigDTO
|
||||
} from "./types";
|
||||
|
||||
export const useDeleteCert = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificate, object, TDeleteCertDTO>({
|
||||
mutationFn: async ({ serialNumber }) => {
|
||||
mutationFn: async ({ id }) => {
|
||||
const {
|
||||
data: { certificate }
|
||||
} = await apiRequest.delete<{ certificate: TCertificate }>(
|
||||
`/api/v1/pki/certificates/${serialNumber}`
|
||||
`/api/v1/cert-manager/certificates/${id}`
|
||||
);
|
||||
return certificate;
|
||||
},
|
||||
onSuccess: (_, { projectSlug }) => {
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.forProjectCertificates(projectSlug)
|
||||
queryKey: ["certificate-profiles", "list"]
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: pkiSubscriberKeys.allPkiSubscriberCertificates()
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.allProjectCertificates()
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.forProjectCertificates(projectId)
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -38,27 +49,29 @@ export const useDeleteCert = () => {
|
||||
export const useRevokeCert = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TCertificate, object, TRevokeCertDTO>({
|
||||
mutationFn: async ({ serialNumber, revocationReason }) => {
|
||||
mutationFn: async ({ id, revocationReason }) => {
|
||||
const {
|
||||
data: { certificate }
|
||||
} = await apiRequest.post<{ certificate: TCertificate }>(
|
||||
`/api/v1/pki/certificates/${serialNumber}/revoke`,
|
||||
`/api/v1/cert-manager/certificates/${id}/revoke`,
|
||||
{
|
||||
revocationReason
|
||||
}
|
||||
);
|
||||
return certificate;
|
||||
},
|
||||
onSuccess: (_, { projectSlug }) => {
|
||||
onSuccess: (_, { projectId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.forProjectCertificates(projectSlug)
|
||||
queryKey: ["certificate-profiles", "list"]
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: pkiSubscriberKeys.allPkiSubscriberCertificates()
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["certificate-profiles", "list"]
|
||||
queryKey: projectKeys.allProjectCertificates()
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.forProjectCertificates(projectId)
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -69,7 +82,7 @@ export const useImportCertificate = () => {
|
||||
return useMutation<TImportCertificateResponse, object, TImportCertificateDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { data } = await apiRequest.post<TImportCertificateResponse>(
|
||||
"/api/v1/pki/certificates/import-certificate",
|
||||
"/api/v1/cert-manager/certificates/import-certificate",
|
||||
body
|
||||
);
|
||||
return data;
|
||||
@@ -87,7 +100,7 @@ export const useRenewCertificate = () => {
|
||||
return useMutation<TRenewCertificateResponse, object, TRenewCertificateDTO>({
|
||||
mutationFn: async ({ certificateId }) => {
|
||||
const { data } = await apiRequest.post<TRenewCertificateResponse>(
|
||||
`/api/v3/pki/certificates/${certificateId}/renew`,
|
||||
`/api/v1/cert-manager/certificates/${certificateId}/renew`,
|
||||
{}
|
||||
);
|
||||
return data;
|
||||
@@ -120,7 +133,7 @@ export const useUpdateRenewalConfig = () => {
|
||||
>({
|
||||
mutationFn: async ({ certificateId, renewBeforeDays, enableAutoRenewal }) => {
|
||||
const { data } = await apiRequest.patch<{ message: string; renewBeforeDays?: number }>(
|
||||
`/api/v3/pki/certificates/${certificateId}/config`,
|
||||
`/api/v1/cert-manager/certificates/${certificateId}/config`,
|
||||
{ renewBeforeDays, enableAutoRenewal }
|
||||
);
|
||||
return data;
|
||||
@@ -138,10 +151,10 @@ export const useUpdateRenewalConfig = () => {
|
||||
|
||||
export const useDownloadCertPkcs12 = () => {
|
||||
return useMutation<void, object, TDownloadPkcs12DTO>({
|
||||
mutationFn: async ({ serialNumber, projectSlug, password, alias }) => {
|
||||
mutationFn: async ({ certificateId, projectSlug, password, alias }) => {
|
||||
try {
|
||||
const response = await apiRequest.post(
|
||||
`/api/v1/pki/certificates/${serialNumber}/pkcs12`,
|
||||
`/api/v1/cert-manager/certificates/${certificateId}/pkcs12`,
|
||||
{
|
||||
password,
|
||||
alias
|
||||
@@ -157,7 +170,7 @@ export const useDownloadCertPkcs12 = () => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `certificate-${serialNumber}.p12`;
|
||||
link.download = `certificate-${certificateId}.p12`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
@@ -174,3 +187,31 @@ export const useDownloadCertPkcs12 = () => {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUnifiedCertificateIssuance = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TUnifiedCertificateIssuanceResponse, object, TUnifiedCertificateIssuanceDTO>({
|
||||
mutationFn: async (body) => {
|
||||
const { projectSlug, ...requestData } = body;
|
||||
const { data } = await apiRequest.post<TUnifiedCertificateIssuanceResponse>(
|
||||
"/api/v1/cert-manager/certificates",
|
||||
requestData
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { projectSlug }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["certificate-profiles", "list"]
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: pkiSubscriberKeys.allPkiSubscriberCertificates()
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.allProjectCertificates()
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.forProjectCertificates(projectSlug)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -7,7 +7,11 @@ import { TCertificate } from "./types";
|
||||
export const certKeys = {
|
||||
getCertById: (serialNumber: string) => [{ serialNumber }, "cert"],
|
||||
getCertBody: (serialNumber: string) => [{ serialNumber }, "certBody"],
|
||||
getCertBundle: (serialNumber: string) => [{ serialNumber }, "certBundle"]
|
||||
getCertBundle: (serialNumber: string) => [{ serialNumber }, "certBundle"],
|
||||
getCertificateRequest: (requestId: string, projectSlug: string) => [
|
||||
{ requestId, projectSlug },
|
||||
"certificateRequest"
|
||||
]
|
||||
};
|
||||
|
||||
export const useGetCert = (serialNumber: string) => {
|
||||
|
||||
@@ -24,13 +24,13 @@ export type TCertificate = {
|
||||
};
|
||||
|
||||
export type TDeleteCertDTO = {
|
||||
projectSlug: string;
|
||||
serialNumber: string;
|
||||
id: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TRevokeCertDTO = {
|
||||
projectSlug: string;
|
||||
serialNumber: string;
|
||||
projectId: string;
|
||||
id: string;
|
||||
revocationReason: string;
|
||||
};
|
||||
|
||||
@@ -64,6 +64,7 @@ export type TRenewCertificateResponse = {
|
||||
serialNumber: string;
|
||||
certificateId: string;
|
||||
projectId: string;
|
||||
certificateRequestId?: string;
|
||||
};
|
||||
|
||||
export type TUpdateRenewalConfigDTO = {
|
||||
@@ -74,8 +75,64 @@ export type TUpdateRenewalConfigDTO = {
|
||||
};
|
||||
|
||||
export type TDownloadPkcs12DTO = {
|
||||
serialNumber: string;
|
||||
certificateId: string;
|
||||
projectSlug: string;
|
||||
password: string;
|
||||
alias: string;
|
||||
};
|
||||
|
||||
export type TUnifiedCertificateIssuanceDTO = {
|
||||
projectSlug: string;
|
||||
profileId: string;
|
||||
projectId: string;
|
||||
csr?: string;
|
||||
attributes?: {
|
||||
commonName?: string;
|
||||
keyUsages?: string[];
|
||||
extendedKeyUsages?: string[];
|
||||
altNames?: Array<{
|
||||
type: string;
|
||||
value: string;
|
||||
}>;
|
||||
signatureAlgorithm: string;
|
||||
keyAlgorithm: string;
|
||||
subjectAlternativeNames?: Array<{
|
||||
type: string;
|
||||
value: string;
|
||||
}>;
|
||||
ttl: string;
|
||||
notBefore?: string;
|
||||
notAfter?: string;
|
||||
};
|
||||
removeRootsFromChain?: boolean;
|
||||
};
|
||||
|
||||
export type TUnifiedCertificateResponse = {
|
||||
certificate: {
|
||||
certificate: string;
|
||||
issuingCaCertificate: string;
|
||||
certificateChain: string;
|
||||
privateKey?: string;
|
||||
serialNumber: string;
|
||||
certificateId: string;
|
||||
};
|
||||
certificateRequestId: string;
|
||||
};
|
||||
|
||||
export type TCertificateRequestResponse = {
|
||||
certificateRequestId: string;
|
||||
status: "pending" | "issued" | "failed";
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type TUnifiedCertificateIssuanceResponse =
|
||||
| TUnifiedCertificateResponse
|
||||
| TCertificateRequestResponse;
|
||||
|
||||
export type TCertificateRequestDetails = {
|
||||
status: "pending" | "issued" | "failed";
|
||||
certificate: TCertificate | null;
|
||||
errorMessage: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
@@ -5,4 +5,4 @@ export {
|
||||
useRemoveUserFromGroup,
|
||||
useUpdateGroup
|
||||
} from "./mutations";
|
||||
export { useGetGroupById, useListGroupUsers } from "./queries";
|
||||
export { useGetGroupById, useListGroupProjects, useListGroupUsers } from "./queries";
|
||||
|
||||
@@ -2,7 +2,14 @@ import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { EFilterReturnedUsers, TGroup, TGroupUser } from "./types";
|
||||
import { OrderByDirection } from "../generic/types";
|
||||
import {
|
||||
EFilterReturnedProjects,
|
||||
EFilterReturnedUsers,
|
||||
TGroup,
|
||||
TGroupProject,
|
||||
TGroupUser
|
||||
} from "./types";
|
||||
|
||||
export const groupKeys = {
|
||||
getGroupById: (groupId: string) => [{ groupId }, "group"] as const,
|
||||
@@ -41,6 +48,29 @@ export const groupKeys = {
|
||||
...groupKeys.forGroupUserMemberships(slug),
|
||||
projectId,
|
||||
{ offset, limit, search, filter }
|
||||
] as const,
|
||||
allGroupProjects: () => ["group-projects"] as const,
|
||||
forGroupProjects: (groupId: string) => [...groupKeys.allGroupProjects(), groupId] as const,
|
||||
specificGroupProjects: ({
|
||||
groupId,
|
||||
offset,
|
||||
limit,
|
||||
search,
|
||||
filter,
|
||||
orderBy,
|
||||
orderDirection
|
||||
}: {
|
||||
groupId: string;
|
||||
offset: number;
|
||||
limit: number;
|
||||
search: string;
|
||||
filter?: EFilterReturnedProjects;
|
||||
orderBy?: string;
|
||||
orderDirection?: OrderByDirection;
|
||||
}) =>
|
||||
[
|
||||
...groupKeys.forGroupProjects(groupId),
|
||||
{ offset, limit, search, filter, orderBy, orderDirection }
|
||||
] as const
|
||||
};
|
||||
|
||||
@@ -148,3 +178,54 @@ export const useListProjectGroupUsers = ({
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useListGroupProjects = ({
|
||||
id,
|
||||
offset = 0,
|
||||
limit = 10,
|
||||
search,
|
||||
filter,
|
||||
orderBy,
|
||||
orderDirection
|
||||
}: {
|
||||
id: string;
|
||||
offset: number;
|
||||
limit: number;
|
||||
search: string;
|
||||
orderBy?: string;
|
||||
orderDirection?: OrderByDirection;
|
||||
filter?: EFilterReturnedProjects;
|
||||
}) => {
|
||||
return useQuery({
|
||||
queryKey: groupKeys.specificGroupProjects({
|
||||
groupId: id,
|
||||
offset,
|
||||
limit,
|
||||
search,
|
||||
filter,
|
||||
orderBy,
|
||||
orderDirection
|
||||
}),
|
||||
enabled: Boolean(id),
|
||||
placeholderData: (previousData) => previousData,
|
||||
queryFn: async () => {
|
||||
const params = new URLSearchParams({
|
||||
offset: String(offset),
|
||||
limit: String(limit),
|
||||
search,
|
||||
...(filter && { filter }),
|
||||
...(orderBy && { orderBy }),
|
||||
...(orderDirection && { orderDirection })
|
||||
});
|
||||
|
||||
const { data } = await apiRequest.get<{ projects: TGroupProject[]; totalCount: number }>(
|
||||
`/api/v1/groups/${id}/projects`,
|
||||
{
|
||||
params
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -52,7 +52,21 @@ export type TGroupUser = {
|
||||
joinedGroupAt: Date;
|
||||
};
|
||||
|
||||
export type TGroupProject = {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
type: string;
|
||||
joinedGroupAt: Date;
|
||||
};
|
||||
|
||||
export enum EFilterReturnedUsers {
|
||||
EXISTING_MEMBERS = "existingMembers",
|
||||
NON_MEMBERS = "nonMembers"
|
||||
}
|
||||
|
||||
export enum EFilterReturnedProjects {
|
||||
ASSIGNED_PROJECTS = "assignedProjects",
|
||||
UNASSIGNED_PROJECTS = "unassignedProjects"
|
||||
}
|
||||
|
||||
@@ -840,9 +840,7 @@ export type CreateTokenIdentityTokenAuthDTO = {
|
||||
|
||||
export type CreateTokenIdentityTokenAuthRes = {
|
||||
accessToken: string;
|
||||
tokenType: string;
|
||||
expiresIn: number;
|
||||
accessTokenMaxTTL: number;
|
||||
tokenData: IdentityAccessToken;
|
||||
};
|
||||
|
||||
export type UpdateTokenIdentityTokenAuthDTO = {
|
||||
|
||||
@@ -5,7 +5,6 @@ export enum IdentityProjectAdditionalPrivilegeTemporaryMode {
|
||||
}
|
||||
|
||||
export type TIdentityProjectPrivilege = {
|
||||
projectMembershipId: string;
|
||||
slug: string;
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
|
||||
@@ -6,6 +6,7 @@ import { kmsKeys } from "./queries";
|
||||
import {
|
||||
AddExternalKmsType,
|
||||
ExternalKmsGcpSchemaType,
|
||||
ExternalKmsProvider,
|
||||
KmsGcpKeyFetchAuthType,
|
||||
KmsType,
|
||||
UpdateExternalKmsType
|
||||
@@ -14,11 +15,12 @@ import {
|
||||
export const useAddExternalKms = (orgId: string) => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ name, description, provider }: AddExternalKmsType) => {
|
||||
const { data } = await apiRequest.post("/api/v1/external-kms", {
|
||||
mutationFn: async ({ name, description, configuration }: AddExternalKmsType) => {
|
||||
const providerPath = configuration.type === ExternalKmsProvider.Aws ? "aws" : "gcp";
|
||||
const { data } = await apiRequest.post(`/api/v1/external-kms/${providerPath}`, {
|
||||
name,
|
||||
description,
|
||||
provider
|
||||
configuration: configuration.inputs
|
||||
});
|
||||
|
||||
return data;
|
||||
@@ -29,21 +31,21 @@ export const useAddExternalKms = (orgId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateExternalKms = (orgId: string) => {
|
||||
export const useUpdateExternalKms = (orgId: string, provider: ExternalKmsProvider) => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
kmsId,
|
||||
name,
|
||||
description,
|
||||
provider
|
||||
configuration
|
||||
}: {
|
||||
kmsId: string;
|
||||
} & UpdateExternalKmsType) => {
|
||||
const { data } = await apiRequest.patch(`/api/v1/external-kms/${kmsId}`, {
|
||||
const { data } = await apiRequest.patch(`/api/v1/external-kms/${provider}/${kmsId}`, {
|
||||
name,
|
||||
description,
|
||||
provider
|
||||
configuration: configuration?.inputs
|
||||
});
|
||||
|
||||
return data;
|
||||
@@ -58,8 +60,8 @@ export const useUpdateExternalKms = (orgId: string) => {
|
||||
export const useRemoveExternalKms = (orgId: string) => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (kmsId: string) => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/external-kms/${kmsId}`);
|
||||
mutationFn: async ({ kmsId, provider }: { kmsId: string; provider: ExternalKmsProvider }) => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/external-kms/${provider}/${kmsId}`);
|
||||
|
||||
return data;
|
||||
},
|
||||
@@ -130,11 +132,19 @@ export const useExternalKmsFetchGcpKeys = (orgId: string) => {
|
||||
);
|
||||
}
|
||||
|
||||
const { data } = await apiRequest.post("/api/v1/external-kms/gcp/keys", {
|
||||
authMethod: credential ? KmsGcpKeyFetchAuthType.Credential : KmsGcpKeyFetchAuthType.Kms,
|
||||
region: gcpRegion,
|
||||
...rest
|
||||
});
|
||||
const requestBody = credential
|
||||
? {
|
||||
authMethod: KmsGcpKeyFetchAuthType.Credential,
|
||||
region: gcpRegion,
|
||||
credential
|
||||
}
|
||||
: {
|
||||
authMethod: KmsGcpKeyFetchAuthType.Kms,
|
||||
region: gcpRegion,
|
||||
kmsId
|
||||
};
|
||||
|
||||
const { data } = await apiRequest.post("/api/v1/external-kms/gcp/keys", requestBody);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { Kms, KmsListEntry } from "./types";
|
||||
import { ExternalKmsProvider, Kms, KmsListEntry } from "./types";
|
||||
|
||||
export const kmsKeys = {
|
||||
getExternalKmsList: (orgId: string) => ["get-all-external-kms", { orgId }],
|
||||
@@ -23,15 +23,19 @@ export const useGetExternalKmsList = (orgId: string, { enabled }: { enabled?: bo
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetExternalKmsById = (kmsId: string) => {
|
||||
export const useGetExternalKmsById = ({
|
||||
kmsId,
|
||||
provider
|
||||
}: {
|
||||
kmsId: string;
|
||||
provider: ExternalKmsProvider;
|
||||
}) => {
|
||||
return useQuery({
|
||||
queryKey: kmsKeys.getExternalKmsById(kmsId),
|
||||
enabled: Boolean(kmsId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { externalKms }
|
||||
} = await apiRequest.get<{ externalKms: Kms }>(`/api/v1/external-kms/${kmsId}`);
|
||||
return externalKms;
|
||||
const { data } = await apiRequest.get<Kms>(`/api/v1/external-kms/${provider}/${kmsId}`);
|
||||
return data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -8,12 +8,13 @@ export type Kms = {
|
||||
description: string;
|
||||
orgId: string;
|
||||
name: string;
|
||||
external: {
|
||||
externalKms: {
|
||||
id: string;
|
||||
status: string;
|
||||
statusDetails: string;
|
||||
provider: string;
|
||||
providerInput: Record<string, any>;
|
||||
configuration: Record<string, any>;
|
||||
credentialsHash?: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -123,14 +124,14 @@ export const ExternalKmsInputSchema = z.discriminatedUnion("type", [
|
||||
export const AddExternalKmsSchema = z.object({
|
||||
name: slugSchema({ min: 1, field: "Alias" }),
|
||||
description: z.string().trim().optional(),
|
||||
provider: ExternalKmsInputSchema
|
||||
configuration: ExternalKmsInputSchema
|
||||
});
|
||||
|
||||
export type AddExternalKmsType = z.infer<typeof AddExternalKmsSchema>;
|
||||
|
||||
// we need separate schema for update because the credential field is not required on GCP
|
||||
export const ExternalKmsUpdateInputSchema = z.discriminatedUnion("type", [
|
||||
z.object({ type: z.literal(ExternalKmsProvider.Aws), inputs: ExternalKmsAwsSchema }),
|
||||
z.object({ type: z.literal(ExternalKmsProvider.Aws), inputs: ExternalKmsAwsSchema.partial() }),
|
||||
z.object({
|
||||
type: z.literal(ExternalKmsProvider.Gcp),
|
||||
inputs: ExternalKmsGcpSchema.pick({ gcpRegion: true, keyName: true })
|
||||
@@ -144,9 +145,10 @@ export const UpdateExternalKmsSchema = z.object({
|
||||
.min(1)
|
||||
.refine((v) => slugify(v) === v, {
|
||||
message: "Alias must be a valid slug"
|
||||
}),
|
||||
})
|
||||
.optional(),
|
||||
description: z.string().trim().optional(),
|
||||
provider: ExternalKmsUpdateInputSchema
|
||||
configuration: ExternalKmsUpdateInputSchema.optional()
|
||||
});
|
||||
|
||||
export type UpdateExternalKmsType = z.infer<typeof UpdateExternalKmsSchema>;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Resources
|
||||
export enum PamResourceType {
|
||||
Postgres = "postgres",
|
||||
MySQL = "mysql",
|
||||
@@ -18,9 +19,24 @@ export enum PamResourceType {
|
||||
DynamoDB = "dynamodb"
|
||||
}
|
||||
|
||||
export enum PamResourceOrderBy {
|
||||
Name = "name"
|
||||
}
|
||||
|
||||
// Sessions
|
||||
export enum PamSessionStatus {
|
||||
Starting = "starting",
|
||||
Active = "active",
|
||||
Ended = "ended",
|
||||
Terminated = "terminated"
|
||||
}
|
||||
|
||||
// Accounts
|
||||
export enum PamAccountOrderBy {
|
||||
Name = "name"
|
||||
}
|
||||
|
||||
export enum PamAccountView {
|
||||
Flat = "flat",
|
||||
Nested = "nested"
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export const useCreatePamResource = () => {
|
||||
return data.resource;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listResources(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listResources({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -48,7 +48,7 @@ export const useUpdatePamResource = () => {
|
||||
return data.resource;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listResources(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listResources({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -64,7 +64,7 @@ export const useDeletePamResource = () => {
|
||||
return data.resource;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listResources(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listResources({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -82,7 +82,7 @@ export const useCreatePamAccount = () => {
|
||||
return data.account;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -99,7 +99,7 @@ export const useUpdatePamAccount = () => {
|
||||
return data.account;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -115,7 +115,7 @@ export const useDeletePamAccount = () => {
|
||||
return data.account;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -130,7 +130,7 @@ export const useCreatePamFolder = () => {
|
||||
return data.folder;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -147,7 +147,7 @@ export const useUpdatePamFolder = () => {
|
||||
return data.folder;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -163,7 +163,7 @@ export const useDeletePamFolder = () => {
|
||||
return data.folder;
|
||||
},
|
||||
onSuccess: ({ projectId }) => {
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts(projectId) });
|
||||
queryClient.invalidateQueries({ queryKey: pamKeys.listAccounts({ projectId }) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -4,7 +4,14 @@ import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { TPamResourceOption } from "./types/resource-options";
|
||||
import { PamResourceType } from "./enums";
|
||||
import { TPamAccount, TPamFolder, TPamResource, TPamSession } from "./types";
|
||||
import {
|
||||
TListPamAccountsDTO,
|
||||
TListPamResourcesDTO,
|
||||
TPamAccount,
|
||||
TPamFolder,
|
||||
TPamResource,
|
||||
TPamSession
|
||||
} from "./types";
|
||||
|
||||
export const pamKeys = {
|
||||
all: ["pam"] as const,
|
||||
@@ -12,14 +19,24 @@ export const pamKeys = {
|
||||
account: () => [...pamKeys.all, "account"] as const,
|
||||
session: () => [...pamKeys.all, "session"] as const,
|
||||
listResourceOptions: () => [...pamKeys.resource(), "options"] as const,
|
||||
listResources: (projectId: string) => [...pamKeys.resource(), "list", projectId],
|
||||
listResources: ({ projectId, ...params }: TListPamResourcesDTO) => [
|
||||
...pamKeys.resource(),
|
||||
"list",
|
||||
projectId,
|
||||
params
|
||||
],
|
||||
getResource: (resourceType: string, resourceId: string) => [
|
||||
...pamKeys.resource(),
|
||||
"get",
|
||||
resourceType,
|
||||
resourceId
|
||||
],
|
||||
listAccounts: (projectId: string) => [...pamKeys.account(), "list", projectId],
|
||||
listAccounts: ({ projectId, ...params }: TListPamAccountsDTO) => [
|
||||
...pamKeys.account(),
|
||||
"list",
|
||||
projectId,
|
||||
params
|
||||
],
|
||||
getSession: (sessionId: string) => [...pamKeys.session(), "get", sessionId],
|
||||
listSessions: (projectId: string) => [...pamKeys.session(), "list", projectId]
|
||||
};
|
||||
@@ -49,28 +66,33 @@ export const useListPamResourceOptions = (
|
||||
});
|
||||
};
|
||||
|
||||
type TListPamResourcesResponse = {
|
||||
resources: TPamResource[];
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
export const useListPamResources = (
|
||||
projectId: string,
|
||||
params: TListPamResourcesDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TPamResource[],
|
||||
TListPamResourcesResponse,
|
||||
unknown,
|
||||
TPamResource[],
|
||||
TListPamResourcesResponse,
|
||||
ReturnType<typeof pamKeys.listResources>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: pamKeys.listResources(projectId),
|
||||
queryKey: pamKeys.listResources(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ resources: TPamResource[] }>(
|
||||
"/api/v1/pam/resources",
|
||||
{ params: { projectId } }
|
||||
);
|
||||
const { data } = await apiRequest.get<TListPamResourcesResponse>("/api/v1/pam/resources", {
|
||||
params
|
||||
});
|
||||
|
||||
return data.resources;
|
||||
return data;
|
||||
},
|
||||
placeholderData: (prev) => prev,
|
||||
...options
|
||||
});
|
||||
};
|
||||
@@ -98,28 +120,36 @@ export const useGetPamResourceById = (
|
||||
};
|
||||
|
||||
// Accounts
|
||||
type TListPamAccountsResponse = {
|
||||
accounts: TPamAccount[];
|
||||
folders: TPamFolder[];
|
||||
totalCount: number;
|
||||
folderId?: string;
|
||||
folderPaths: Record<string, string>;
|
||||
};
|
||||
|
||||
export const useListPamAccounts = (
|
||||
projectId: string,
|
||||
params: TListPamAccountsDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
{ accounts: TPamAccount[]; folders: TPamFolder[] },
|
||||
TListPamAccountsResponse,
|
||||
unknown,
|
||||
{ accounts: TPamAccount[]; folders: TPamFolder[] },
|
||||
TListPamAccountsResponse,
|
||||
ReturnType<typeof pamKeys.listAccounts>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: pamKeys.listAccounts(projectId),
|
||||
queryKey: pamKeys.listAccounts(params),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{ accounts: TPamAccount[]; folders: TPamFolder[] }>(
|
||||
"/api/v1/pam/accounts",
|
||||
{ params: { projectId } }
|
||||
);
|
||||
const { data } = await apiRequest.get<TListPamAccountsResponse>("/api/v1/pam/accounts", {
|
||||
params
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
placeholderData: (prev) => prev,
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { PamResourceType, PamSessionStatus } from "../enums";
|
||||
import { OrderByDirection } from "../../generic/types";
|
||||
import {
|
||||
PamAccountOrderBy,
|
||||
PamAccountView,
|
||||
PamResourceOrderBy,
|
||||
PamResourceType,
|
||||
PamSessionStatus
|
||||
} from "../enums";
|
||||
import { TMySQLAccount, TMySQLResource } from "./mysql-resource";
|
||||
import { TPostgresAccount, TPostgresResource } from "./postgres-resource";
|
||||
import { TSSHAccount, TSSHResource } from "./ssh-resource";
|
||||
|
||||
export * from "./mysql-resource";
|
||||
export * from "./postgres-resource";
|
||||
export * from "./ssh-resource";
|
||||
|
||||
export type TPamResource = TPostgresResource | TMySQLResource;
|
||||
export type TPamResource = TPostgresResource | TMySQLResource | TSSHResource;
|
||||
|
||||
export type TPamAccount = TPostgresAccount | TMySQLAccount;
|
||||
export type TPamAccount = TPostgresAccount | TMySQLAccount | TSSHAccount;
|
||||
|
||||
export type TPamFolder = {
|
||||
id: string;
|
||||
@@ -19,6 +28,22 @@ export type TPamFolder = {
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
// Session log types
|
||||
export type TPamCommandLog = {
|
||||
input: string;
|
||||
output: string;
|
||||
timestamp: string;
|
||||
};
|
||||
|
||||
export type TTerminalEvent = {
|
||||
timestamp: string;
|
||||
eventType: "input" | "output" | "resize" | "error";
|
||||
data: string; // Base64 encoded binary data
|
||||
elapsedTime: number; // Seconds since session start (for replay)
|
||||
};
|
||||
|
||||
export type TPamSessionLog = TPamCommandLog | TTerminalEvent;
|
||||
|
||||
export type TPamSession = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
@@ -37,14 +62,20 @@ export type TPamSession = {
|
||||
endedAt?: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
commandLogs: {
|
||||
input: string;
|
||||
output: string;
|
||||
timestamp: string;
|
||||
}[];
|
||||
logs: TPamSessionLog[];
|
||||
};
|
||||
|
||||
// Resource DTOs
|
||||
export type TListPamResourcesDTO = {
|
||||
projectId: string;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
orderBy?: PamResourceOrderBy;
|
||||
orderDirection?: OrderByDirection;
|
||||
search?: string;
|
||||
filterResourceTypes?: string;
|
||||
};
|
||||
|
||||
export type TCreatePamResourceDTO = Pick<
|
||||
TPamResource,
|
||||
"name" | "connectionDetails" | "resourceType" | "gatewayId" | "projectId"
|
||||
@@ -63,6 +94,18 @@ export type TDeletePamResourceDTO = {
|
||||
};
|
||||
|
||||
// Account DTOs
|
||||
export type TListPamAccountsDTO = {
|
||||
projectId: string;
|
||||
accountPath?: string | null;
|
||||
accountView?: PamAccountView;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
orderBy?: PamAccountOrderBy;
|
||||
orderDirection?: OrderByDirection;
|
||||
search?: string;
|
||||
filterResourceIds?: string;
|
||||
};
|
||||
|
||||
export type TCreatePamAccountDTO = Pick<
|
||||
TPamAccount,
|
||||
"name" | "description" | "credentials" | "projectId" | "resourceId" | "folderId"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { PamResourceType } from "../enums";
|
||||
import { TBasePamAccount } from "./base-account";
|
||||
import { TBasePamResource } from "./base-resource";
|
||||
|
||||
export enum SSHAuthMethod {
|
||||
Password = "password",
|
||||
PublicKey = "public-key",
|
||||
Certificate = "certificate"
|
||||
}
|
||||
|
||||
export type TSSHConnectionDetails = {
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
|
||||
export type TSSHPasswordCredentials = {
|
||||
authMethod: SSHAuthMethod.Password;
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type TSSHPublicKeyCredentials = {
|
||||
authMethod: SSHAuthMethod.PublicKey;
|
||||
username: string;
|
||||
privateKey: string;
|
||||
};
|
||||
|
||||
export type TSSHCertificateCredentials = {
|
||||
authMethod: SSHAuthMethod.Certificate;
|
||||
username: string;
|
||||
};
|
||||
|
||||
export type TSSHCredentials =
|
||||
| TSSHPasswordCredentials
|
||||
| TSSHPublicKeyCredentials
|
||||
| TSSHCertificateCredentials;
|
||||
|
||||
// Resources
|
||||
export type TSSHResource = TBasePamResource & { resourceType: PamResourceType.SSH } & {
|
||||
connectionDetails: TSSHConnectionDetails;
|
||||
rotationAccountCredentials?: TSSHCredentials | null;
|
||||
};
|
||||
|
||||
// Accounts
|
||||
export type TSSHAccount = TBasePamAccount & {
|
||||
credentials: TSSHCredentials;
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import { projectKeys } from "../projects";
|
||||
import { pkiAlertKeys } from "./queries";
|
||||
import { TCreatePkiAlertDTO, TDeletePkiAlertDTO, TPkiAlert, TUpdatePkiAlertDTO } from "./types";
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useCreatePkiAlert = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TPkiAlert, object, TCreatePkiAlertDTO>({
|
||||
@@ -19,6 +20,7 @@ export const useCreatePkiAlert = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useUpdatePkiAlert = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TPkiAlert, object, TUpdatePkiAlertDTO>({
|
||||
@@ -36,6 +38,7 @@ export const useUpdatePkiAlert = () => {
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useDeletePkiAlert = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<TPkiAlert, object, TDeletePkiAlertDTO>({
|
||||
|
||||
@@ -8,6 +8,7 @@ export const pkiAlertKeys = {
|
||||
getPkiAlertById: (alertId: string) => [{ alertId }, "alert"]
|
||||
};
|
||||
|
||||
// TODO: DEPRECATE
|
||||
export const useGetPkiAlertById = (alertId: string) => {
|
||||
return useQuery({
|
||||
queryKey: pkiAlertKeys.getPkiAlertById(alertId),
|
||||
|
||||
@@ -11,7 +11,7 @@ export const useCreatePkiAlertV2 = () => {
|
||||
return useMutation<TPkiAlertV2, unknown, TCreatePkiAlertV2>({
|
||||
mutationFn: async (data) => {
|
||||
const { data: response } = await apiRequest.post<{ alert: TPkiAlertV2 }>(
|
||||
"/api/v2/pki/alerts",
|
||||
"/api/v1/cert-manager/alerts",
|
||||
data
|
||||
);
|
||||
return response.alert;
|
||||
@@ -30,7 +30,7 @@ export const useUpdatePkiAlertV2 = () => {
|
||||
return useMutation<TPkiAlertV2, unknown, TUpdatePkiAlertV2>({
|
||||
mutationFn: async ({ alertId, ...data }) => {
|
||||
const { data: response } = await apiRequest.patch<{ alert: TPkiAlertV2 }>(
|
||||
`/api/v2/pki/alerts/${alertId}`,
|
||||
`/api/v1/cert-manager/alerts/${alertId}`,
|
||||
data
|
||||
);
|
||||
return response.alert;
|
||||
@@ -52,7 +52,7 @@ export const useDeletePkiAlertV2 = () => {
|
||||
return useMutation<TPkiAlertV2, unknown, TDeletePkiAlertV2>({
|
||||
mutationFn: async ({ alertId }) => {
|
||||
const { data } = await apiRequest.delete<{ alert: TPkiAlertV2 }>(
|
||||
`/api/v2/pki/alerts/${alertId}`
|
||||
`/api/v1/cert-manager/alerts/${alertId}`
|
||||
);
|
||||
return data.alert;
|
||||
},
|
||||
|
||||
@@ -24,14 +24,16 @@ export const pkiAlertsV2Keys = {
|
||||
};
|
||||
|
||||
const fetchPkiAlertsV2 = async (params: TGetPkiAlertsV2): Promise<TGetPkiAlertsV2Response> => {
|
||||
const { data } = await apiRequest.get<TGetPkiAlertsV2Response>("/api/v2/pki/alerts", {
|
||||
const { data } = await apiRequest.get<TGetPkiAlertsV2Response>("/api/v1/cert-manager/alerts", {
|
||||
params
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
const fetchPkiAlertV2ById = async ({ alertId }: TGetPkiAlertV2ById): Promise<TPkiAlertV2> => {
|
||||
const { data } = await apiRequest.get<{ alert: TPkiAlertV2 }>(`/api/v2/pki/alerts/${alertId}`);
|
||||
const { data } = await apiRequest.get<{ alert: TPkiAlertV2 }>(
|
||||
`/api/v1/cert-manager/alerts/${alertId}`
|
||||
);
|
||||
return data.alert;
|
||||
};
|
||||
|
||||
@@ -40,7 +42,7 @@ const fetchPkiAlertV2MatchingCertificates = async (
|
||||
): Promise<TGetPkiAlertV2MatchingCertificatesResponse> => {
|
||||
const { alertId, ...queryParams } = params;
|
||||
const { data } = await apiRequest.get<TGetPkiAlertV2MatchingCertificatesResponse>(
|
||||
`/api/v2/pki/alerts/${alertId}/certificates`,
|
||||
`/api/v1/cert-manager/alerts/${alertId}/certificates`,
|
||||
{ params: queryParams }
|
||||
);
|
||||
return data;
|
||||
@@ -50,7 +52,7 @@ const fetchPkiAlertV2CurrentMatchingCertificates = async (
|
||||
params: TGetPkiAlertV2CurrentMatchingCertificates
|
||||
): Promise<TGetPkiAlertV2CurrentMatchingCertificatesResponse> => {
|
||||
const { data } = await apiRequest.post<TGetPkiAlertV2CurrentMatchingCertificatesResponse>(
|
||||
"/api/v2/pki/alerts/preview/certificates",
|
||||
"/api/v1/cert-manager/alerts/preview/certificates",
|
||||
params
|
||||
);
|
||||
return data;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export enum PkiSync {
|
||||
AzureKeyVault = "azure-key-vault",
|
||||
AwsCertificateManager = "aws-certificate-manager"
|
||||
AwsCertificateManager = "aws-certificate-manager",
|
||||
AwsSecretsManager = "aws-secrets-manager",
|
||||
Chef = "chef"
|
||||
}
|
||||
|
||||
export enum PkiSyncStatus {
|
||||
@@ -12,7 +14,7 @@ export enum PkiSyncStatus {
|
||||
|
||||
export enum CertificateSyncStatus {
|
||||
Pending = "pending",
|
||||
Syncing = "syncing",
|
||||
Running = "running",
|
||||
Succeeded = "succeeded",
|
||||
Failed = "failed"
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ export const useCreatePkiSync = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ destination, ...params }: TCreatePkiSyncDTO) => {
|
||||
const { data } = await apiRequest.post<TPkiSync>(`/api/v1/pki/syncs/${destination}`, params);
|
||||
const { data } = await apiRequest.post<TPkiSync>(
|
||||
`/api/v1/cert-manager/syncs/${destination}`,
|
||||
params
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
@@ -31,7 +34,7 @@ export const useUpdatePkiSync = () => {
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, projectId, destination, ...params }: TUpdatePkiSyncDTO) => {
|
||||
const { data } = await apiRequest.patch<TPkiSync>(
|
||||
`/api/v1/pki/syncs/${destination}/${syncId}`,
|
||||
`/api/v1/cert-manager/syncs/${destination}/${syncId}`,
|
||||
params,
|
||||
{ params: { projectId } }
|
||||
);
|
||||
@@ -49,9 +52,12 @@ export const useDeletePkiSync = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, projectId, destination }: TDeletePkiSyncDTO) => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/pki/syncs/${destination}/${syncId}`, {
|
||||
params: { projectId }
|
||||
});
|
||||
const { data } = await apiRequest.delete(
|
||||
`/api/v1/cert-manager/syncs/${destination}/${syncId}`,
|
||||
{
|
||||
params: { projectId }
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
@@ -66,7 +72,9 @@ export const useTriggerPkiSyncSyncCertificates = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination }: TTriggerPkiSyncSyncCertificatesDTO) => {
|
||||
const { data } = await apiRequest.post(`/api/v1/pki/syncs/${destination}/${syncId}/sync`);
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/cert-manager/syncs/${destination}/${syncId}/sync`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
@@ -111,7 +119,9 @@ export const useTriggerPkiSyncImportCertificates = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination }: TTriggerPkiSyncImportCertificatesDTO) => {
|
||||
const { data } = await apiRequest.post(`/api/v1/pki/syncs/${destination}/${syncId}/import`);
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/cert-manager/syncs/${destination}/${syncId}/import`
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
@@ -157,7 +167,7 @@ export const useTriggerPkiSyncRemoveCertificates = () => {
|
||||
return useMutation({
|
||||
mutationFn: async ({ syncId, destination }: TTriggerPkiSyncRemoveCertificatesDTO) => {
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/pki/syncs/${destination}/${syncId}/remove-certificates`
|
||||
`/api/v1/cert-manager/syncs/${destination}/${syncId}/remove-certificates`
|
||||
);
|
||||
|
||||
return data;
|
||||
@@ -209,9 +219,12 @@ export const useAddCertificatesToPkiSync = () => {
|
||||
pkiSyncId: string;
|
||||
certificateIds: string[];
|
||||
}) => {
|
||||
const { data } = await apiRequest.post(`/api/v1/pki/syncs/${pkiSyncId}/certificates`, {
|
||||
certificateIds
|
||||
});
|
||||
const { data } = await apiRequest.post(
|
||||
`/api/v1/cert-manager/syncs/${pkiSyncId}/certificates`,
|
||||
{
|
||||
certificateIds
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
@@ -231,9 +244,12 @@ export const useRemoveCertificatesFromPkiSync = () => {
|
||||
pkiSyncId: string;
|
||||
certificateIds: string[];
|
||||
}) => {
|
||||
const { data } = await apiRequest.delete(`/api/v1/pki/syncs/${pkiSyncId}/certificates`, {
|
||||
data: { certificateIds }
|
||||
});
|
||||
const { data } = await apiRequest.delete(
|
||||
`/api/v1/cert-manager/syncs/${pkiSyncId}/certificates`,
|
||||
{
|
||||
data: { certificateIds }
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -37,7 +37,9 @@ export const usePkiSyncOptions = (
|
||||
return useQuery({
|
||||
queryKey: pkiSyncKeys.options(),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TListPkiSyncOptions>("/api/v1/pki/syncs/options");
|
||||
const { data } = await apiRequest.get<TListPkiSyncOptions>(
|
||||
"/api/v1/cert-manager/syncs/options"
|
||||
);
|
||||
|
||||
return data.pkiSyncOptions;
|
||||
},
|
||||
@@ -58,7 +60,7 @@ export const fetchPkiSyncsByProjectId = async (projectId: string, certificateId?
|
||||
params.certificateId = certificateId;
|
||||
}
|
||||
|
||||
const { data } = await apiRequest.get<TListPkiSyncs>("/api/v1/pki/syncs", {
|
||||
const { data } = await apiRequest.get<TListPkiSyncs>("/api/v1/cert-manager/syncs", {
|
||||
params
|
||||
});
|
||||
|
||||
@@ -110,7 +112,7 @@ export const useGetPkiSync = (
|
||||
return useQuery({
|
||||
queryKey: pkiSyncKeys.byId(syncId, projectId),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<TPkiSync>(`/api/v1/pki/syncs/${syncId}`, {
|
||||
const { data } = await apiRequest.get<TPkiSync>(`/api/v1/cert-manager/syncs/${syncId}`, {
|
||||
params: { projectId }
|
||||
});
|
||||
|
||||
@@ -138,7 +140,7 @@ export const useListPkiSyncCertificates = (
|
||||
return useQuery({
|
||||
queryKey: pkiSyncKeys.certificates(syncId, { offset, limit }),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get(`/api/v1/pki/syncs/${syncId}/certificates`, {
|
||||
const { data } = await apiRequest.get(`/api/v1/cert-manager/syncs/${syncId}/certificates`, {
|
||||
params: { offset, limit }
|
||||
});
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
import { PkiSync } from "../enums";
|
||||
import { TRootPkiSync } from "./common";
|
||||
|
||||
export type TAwsSecretsManagerFieldMappings = {
|
||||
certificate: string;
|
||||
privateKey: string;
|
||||
certificateChain: string;
|
||||
caCertificate: string;
|
||||
};
|
||||
|
||||
export type TAwsSecretsManagerPkiSync = TRootPkiSync & {
|
||||
destination: PkiSync.AwsSecretsManager;
|
||||
destinationConfig: {
|
||||
region: string;
|
||||
keyId?: string;
|
||||
};
|
||||
connection: {
|
||||
app: AppConnection.AWS;
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
syncOptions: TRootPkiSync["syncOptions"] & {
|
||||
fieldMappings?: TAwsSecretsManagerFieldMappings;
|
||||
preserveSecretOnRenewal?: boolean;
|
||||
updateExistingCertificates?: boolean;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
import { PkiSync } from "../enums";
|
||||
import { TRootPkiSync } from "./common";
|
||||
|
||||
export type TChefPkiSync = TRootPkiSync & {
|
||||
destination: PkiSync.Chef;
|
||||
destinationConfig: {
|
||||
dataBagName: string;
|
||||
};
|
||||
connection: {
|
||||
app: AppConnection.Chef;
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
@@ -2,11 +2,23 @@ import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
import { CertificateSyncStatus, PkiSyncStatus } from "../enums";
|
||||
|
||||
export type TChefFieldMappings = {
|
||||
certificate: string;
|
||||
privateKey: string;
|
||||
certificateChain: string;
|
||||
caCertificate: string;
|
||||
};
|
||||
|
||||
export type RootPkiSyncOptions = {
|
||||
canImportCertificates: boolean;
|
||||
canRemoveCertificates: boolean;
|
||||
certificateNamePrefix?: string;
|
||||
certificateNameSchema?: string;
|
||||
preserveArn?: boolean;
|
||||
enableVersioning?: boolean;
|
||||
preserveItemOnRenewal?: boolean;
|
||||
updateExistingCertificates?: boolean;
|
||||
fieldMappings?: TChefFieldMappings;
|
||||
};
|
||||
|
||||
export type TRootPkiSync = {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { PkiSync } from "@app/hooks/api/pkiSyncs";
|
||||
|
||||
import { TAwsCertificateManagerPkiSync } from "./aws-certificate-manager-sync";
|
||||
import { TAwsSecretsManagerPkiSync } from "./aws-secrets-manager-sync";
|
||||
import { TAzureKeyVaultPkiSync } from "./azure-key-vault-sync";
|
||||
import { TChefPkiSync } from "./chef-sync";
|
||||
|
||||
export type TPkiSyncOption = {
|
||||
name: string;
|
||||
@@ -16,7 +18,11 @@ export type TPkiSyncOption = {
|
||||
minCertificateNameLength?: number;
|
||||
};
|
||||
|
||||
export type TPkiSync = TAzureKeyVaultPkiSync | TAwsCertificateManagerPkiSync;
|
||||
export type TPkiSync =
|
||||
| TAzureKeyVaultPkiSync
|
||||
| TAwsCertificateManagerPkiSync
|
||||
| TAwsSecretsManagerPkiSync
|
||||
| TChefPkiSync;
|
||||
|
||||
export type TListPkiSyncs = { pkiSyncs: TPkiSync[] };
|
||||
|
||||
@@ -31,6 +37,17 @@ type TCreatePkiSyncDTOBase = {
|
||||
canRemoveCertificates: boolean;
|
||||
certificateNamePrefix?: string;
|
||||
certificateNameSchema?: string;
|
||||
preserveArn?: boolean;
|
||||
enableVersioning?: boolean;
|
||||
preserveItemOnRenewal?: boolean;
|
||||
updateExistingCertificates?: boolean;
|
||||
preserveSecretOnRenewal?: boolean;
|
||||
fieldMappings?: {
|
||||
certificate: string;
|
||||
privateKey: string;
|
||||
certificateChain: string;
|
||||
caCertificate: string;
|
||||
};
|
||||
};
|
||||
isAutoSyncEnabled: boolean;
|
||||
subscriberId?: string | null;
|
||||
@@ -43,6 +60,7 @@ export type TCreatePkiSyncDTO = TCreatePkiSyncDTOBase & {
|
||||
destinationConfig: {
|
||||
vaultBaseUrl?: string;
|
||||
region?: string;
|
||||
dataBagName?: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -76,5 +94,7 @@ export type TTriggerPkiSyncRemoveCertificatesDTO = {
|
||||
};
|
||||
|
||||
export * from "./aws-certificate-manager-sync";
|
||||
export * from "./aws-secrets-manager-sync";
|
||||
export * from "./azure-key-vault-sync";
|
||||
export * from "./chef-sync";
|
||||
export * from "./common";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { groupKeys } from "../groups/queries";
|
||||
import { userKeys } from "../users/query-keys";
|
||||
import { projectKeys } from "./query-keys";
|
||||
import {
|
||||
@@ -30,10 +31,11 @@ export const useAddGroupToWorkspace = () => {
|
||||
|
||||
return groupMembership;
|
||||
},
|
||||
onSuccess: (_, { projectId }) => {
|
||||
onSuccess: (_, { projectId, groupId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectGroupMemberships(projectId)
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: groupKeys.forGroupProjects(groupId) });
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -77,11 +79,13 @@ export const useDeleteGroupFromWorkspace = () => {
|
||||
} = await apiRequest.delete(`/api/v1/projects/${projectId}/groups/${groupId}`);
|
||||
return groupMembership;
|
||||
},
|
||||
onSuccess: (_, { projectId, username }) => {
|
||||
onSuccess: (_, { projectId, username, groupId }) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: projectKeys.getProjectGroupMemberships(projectId)
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: groupKeys.forGroupProjects(groupId) });
|
||||
|
||||
if (username) {
|
||||
queryClient.invalidateQueries({ queryKey: userKeys.listUserGroupMemberships(username) });
|
||||
}
|
||||
|
||||
@@ -191,12 +191,15 @@ export const fetchWorkspaceIntegrations = async (projectId: string) => {
|
||||
return data.integrations;
|
||||
};
|
||||
|
||||
export const useGetWorkspaceIntegrations = (projectId: string) =>
|
||||
export const useGetWorkspaceIntegrations = (
|
||||
projectId: string,
|
||||
options?: { enabled?: boolean; refetchInterval?: number | false }
|
||||
) =>
|
||||
useQuery({
|
||||
queryKey: projectKeys.getProjectIntegrations(projectId),
|
||||
queryFn: () => fetchWorkspaceIntegrations(projectId),
|
||||
enabled: Boolean(projectId),
|
||||
refetchInterval: 4000
|
||||
enabled: Boolean(projectId) && (options?.enabled ?? true),
|
||||
refetchInterval: options?.refetchInterval ?? 4000
|
||||
});
|
||||
|
||||
export const createWorkspace = (
|
||||
|
||||
@@ -338,7 +338,7 @@ export const clearSession = (keepQueryClient?: boolean) => {
|
||||
sessionStorage.removeItem(SessionStorageKeys.CLI_TERMINAL_TOKEN);
|
||||
|
||||
if (!keepQueryClient) {
|
||||
qc.clear(); // Clear React Query cache
|
||||
qc.invalidateQueries();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+10
-14
@@ -1,9 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@import "@fontsource/inter/400.css" layer(base);
|
||||
@import "@fontsource/inter/500.css" layer(base);
|
||||
@import "@fontsource/inter/700.css" layer(base);
|
||||
|
||||
@source not "../public";
|
||||
|
||||
/*
|
||||
@@ -29,11 +25,11 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: var(--font-inter);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--background: oklch(0.145 0 0);
|
||||
font-family: var(--font-inter);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--background: oklch(0.145 0 0);
|
||||
|
||||
--toastify-color-dark: var(--color-mineshaft-700);
|
||||
--toastify-color-dark: var(--color-mineshaft-700);
|
||||
}
|
||||
|
||||
@theme {
|
||||
@@ -45,16 +41,16 @@
|
||||
--color-background: #19191c;
|
||||
--color-foreground: white;
|
||||
--color-success: #2ecc71;
|
||||
--color-info: #34c2db;
|
||||
--color-info: #63b0bd;
|
||||
--color-warning: #f1c40f;
|
||||
--color-danger: #e74c3c;
|
||||
--color-org: #30B3FF;
|
||||
--color-org: #30b3ff;
|
||||
--color-sub-org: #96ff59;
|
||||
--color-project: #e0ed34;
|
||||
--color-neutral: #adaeb0;
|
||||
|
||||
/*legacy color schema */
|
||||
--color-org-v1: #30B3FF;
|
||||
--color-org-v1: #30b3ff;
|
||||
--color-namespace-v1: #96ff59;
|
||||
|
||||
/* Primary */
|
||||
@@ -418,15 +414,15 @@
|
||||
}
|
||||
|
||||
.Toastify__toast {
|
||||
@apply rounded-md;
|
||||
@apply rounded-md;
|
||||
}
|
||||
|
||||
.Toastify__toast-body {
|
||||
@apply items-start;
|
||||
@apply items-start;
|
||||
}
|
||||
|
||||
.Toastify__toast-icon {
|
||||
@apply w-4 pt-1;
|
||||
@apply w-4 pt-1;
|
||||
}
|
||||
|
||||
.tags-conic-bg {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { faMobile } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Outlet } from "@tanstack/react-router";
|
||||
|
||||
import { Banner } from "@app/components/page-frames/Banner";
|
||||
@@ -15,7 +12,6 @@ import { InsecureConnectionBanner } from "../OrganizationLayout/components/Insec
|
||||
import { AdminNavBar } from "./AdminNavBar";
|
||||
|
||||
export const AdminLayout = () => {
|
||||
const { t } = useTranslation();
|
||||
const { config } = useServerConfig();
|
||||
const { data: serverDetails, isLoading } = useFetchServerStatus();
|
||||
const { subscription } = useSubscription();
|
||||
@@ -26,7 +22,7 @@ export const AdminLayout = () => {
|
||||
<>
|
||||
<Banner />
|
||||
<div
|
||||
className={`dark hidden ${containerHeight} w-full flex-col overflow-x-hidden bg-bunker-800 transition-all md:flex`}
|
||||
className={`dark ${containerHeight} flex w-full flex-col overflow-x-hidden bg-bunker-800 transition-all`}
|
||||
>
|
||||
<Navbar />
|
||||
{!isLoading && !serverDetails?.redisConfigured && <RedisBanner />}
|
||||
@@ -40,12 +36,6 @@ export const AdminLayout = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="z-200 flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 md:hidden">
|
||||
<FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" />
|
||||
<p className="max-w-sm px-6 text-center text-lg text-gray-200">
|
||||
{` ${t("common.no-mobile")} `}
|
||||
</p>
|
||||
</div>
|
||||
<Banner />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Link, useMatchRoute } from "@tanstack/react-router";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { Tab, TabList, Tabs, Tooltip } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
|
||||
const generalTabs = [
|
||||
{
|
||||
@@ -60,6 +61,7 @@ const generalTabs = [
|
||||
|
||||
export const AdminNavBar = () => {
|
||||
const matchRoute = useMatchRoute();
|
||||
const { currentOrg } = useOrganization();
|
||||
|
||||
return (
|
||||
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
|
||||
@@ -74,7 +76,7 @@ export const AdminNavBar = () => {
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Tooltip position="bottom" content="Back to organization">
|
||||
<Link to="/organization/projects">
|
||||
<Link to="/organizations/$orgId/projects" params={{ orgId: currentOrg.id }}>
|
||||
<Tab value="back">
|
||||
<FontAwesomeIcon icon={faArrowLeft} />
|
||||
</Tab>
|
||||
|
||||
@@ -2,19 +2,20 @@ import { Link, Outlet, useLocation } from "@tanstack/react-router";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
import { Tab, TabList, Tabs } from "@app/components/v2";
|
||||
import { useProject, useProjectPermission } from "@app/context";
|
||||
import { useOrganization, useProject, useProjectPermission } from "@app/context";
|
||||
|
||||
import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner";
|
||||
|
||||
export const KmsLayout = () => {
|
||||
const { currentProject } = useProject();
|
||||
const { currentOrg } = useOrganization();
|
||||
const { assumedPrivilegeDetails } = useProjectPermission();
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<div className="dark hidden h-full w-full flex-col overflow-x-hidden md:flex">
|
||||
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
|
||||
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
|
||||
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
|
||||
<motion.div
|
||||
key="menu-project-items"
|
||||
initial={{ x: -150 }}
|
||||
@@ -27,24 +28,27 @@ export const KmsLayout = () => {
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Link
|
||||
to="/projects/kms/$projectId/overview"
|
||||
to="/organizations/$orgId/projects/kms/$projectId/overview"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Overview</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/projects/kms/$projectId/kmip"
|
||||
to="/organizations/$orgId/projects/kms/$projectId/kmip"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>KMIP</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/projects/kms/$projectId/access-management"
|
||||
to="/organizations/$orgId/projects/kms/$projectId/access-management"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
@@ -62,16 +66,18 @@ export const KmsLayout = () => {
|
||||
)}
|
||||
</Link>
|
||||
<Link
|
||||
to="/projects/kms/$projectId/audit-logs"
|
||||
to="/organizations/$orgId/projects/kms/$projectId/audit-logs"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
{({ isActive }) => <Tab value={isActive ? "selected" : ""}>Audit Logs</Tab>}
|
||||
</Link>
|
||||
<Link
|
||||
to="/projects/kms/$projectId/settings"
|
||||
to="/organizations/$orgId/projects/kms/$projectId/settings"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId: currentProject.id
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { faMobile } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Outlet, useParams } from "@tanstack/react-router";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
@@ -27,8 +24,6 @@ export const OrganizationLayout = () => {
|
||||
|
||||
const { popUp, handlePopUpToggle } = usePopUp(["createOrg"] as const);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const containerHeight = config.pageFrameContent ? "h-[94vh]" : "h-screen";
|
||||
|
||||
const { data: serverDetails, isLoading } = useFetchServerStatus();
|
||||
@@ -38,7 +33,7 @@ export const OrganizationLayout = () => {
|
||||
<>
|
||||
<Banner />
|
||||
<div
|
||||
className={`dark hidden ${containerHeight} w-full flex-col overflow-x-hidden bg-bunker-800 transition-all md:flex`}
|
||||
className={`dark ${containerHeight} flex w-full flex-col overflow-x-hidden bg-bunker-800 transition-all`}
|
||||
>
|
||||
<Navbar />
|
||||
<div className="flex grow flex-col overflow-y-hidden">
|
||||
@@ -61,12 +56,6 @@ export const OrganizationLayout = () => {
|
||||
isOpen={popUp?.createOrg?.isOpen}
|
||||
onClose={() => handlePopUpToggle("createOrg", false)}
|
||||
/>
|
||||
<div className="z-200 flex h-screen w-screen flex-col items-center justify-center bg-bunker-800 md:hidden">
|
||||
<FontAwesomeIcon icon={faMobile} className="mb-8 text-7xl text-gray-300" />
|
||||
<p className="max-w-sm px-6 text-center text-lg text-gray-200">
|
||||
{` ${t("common.no-mobile")} `}
|
||||
</p>
|
||||
</div>
|
||||
<Banner />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -16,18 +16,21 @@ import {
|
||||
faSignOut,
|
||||
faToolbox,
|
||||
faUser,
|
||||
faUserCog,
|
||||
faUserPlus,
|
||||
faUsers
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Link, useLocation, useNavigate, useRouter, useRouterState } from "@tanstack/react-router";
|
||||
import { Link, useLocation, useNavigate, useRouter } from "@tanstack/react-router";
|
||||
import { ChevronRight, UserPlusIcon } from "lucide-react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { Mfa } from "@app/components/auth/Mfa";
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import SecurityClient from "@app/components/utilities/SecurityClient";
|
||||
import {
|
||||
BreadcrumbContainer,
|
||||
Button,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -39,12 +42,17 @@ import {
|
||||
IconButton,
|
||||
Modal,
|
||||
ModalContent,
|
||||
TBreadcrumbFormat,
|
||||
Tooltip
|
||||
} from "@app/components/v2";
|
||||
import { Badge, InstanceIcon, OrgIcon, SubOrgIcon } from "@app/components/v3";
|
||||
import { envConfig } from "@app/config/env";
|
||||
import { useOrganization, useSubscription, useUser } from "@app/context";
|
||||
import {
|
||||
OrgPermissionActions,
|
||||
OrgPermissionSubjects,
|
||||
useOrganization,
|
||||
useSubscription,
|
||||
useUser
|
||||
} from "@app/context";
|
||||
import { isInfisicalCloud } from "@app/helpers/platform";
|
||||
import { useToggle } from "@app/hooks";
|
||||
import {
|
||||
@@ -59,6 +67,7 @@ import { MfaMethod } from "@app/hooks/api/auth/types";
|
||||
import { getAuthToken } from "@app/hooks/api/reactQuery";
|
||||
import { Organization, SubscriptionPlan } from "@app/hooks/api/types";
|
||||
import { AuthMethod } from "@app/hooks/api/users/types";
|
||||
import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect";
|
||||
import { navigateUserToOrg } from "@app/pages/auth/LoginPage/Login.utils";
|
||||
|
||||
import { ServerAdminsPanel } from "../ServerAdminsPanel/ServerAdminsPanel";
|
||||
@@ -173,13 +182,7 @@ export const Navbar = () => {
|
||||
}
|
||||
}, [subscription, isBillingPage, isModalIntrusive]);
|
||||
|
||||
const matches = useRouterState({ select: (s) => s.matches.at(-1)?.context });
|
||||
const breadcrumbs = matches && "breadcrumbs" in matches ? matches.breadcrumbs : undefined;
|
||||
|
||||
const handleOrgChange = async (orgId: string) => {
|
||||
queryClient.removeQueries({ queryKey: authKeys.getAuthToken });
|
||||
queryClient.removeQueries({ queryKey: projectKeys.getAllUserProjects() });
|
||||
|
||||
const { token, isMfaEnabled, mfaMethod } = await selectOrganization({
|
||||
organizationId: orgId
|
||||
});
|
||||
@@ -196,6 +199,8 @@ export const Navbar = () => {
|
||||
await router.invalidate();
|
||||
await navigateUserToOrg(navigate, orgId);
|
||||
queryClient.removeQueries({ queryKey: subOrgQuery.queryKey });
|
||||
queryClient.removeQueries({ queryKey: authKeys.getAuthToken });
|
||||
queryClient.removeQueries({ queryKey: projectKeys.getAllUserProjects() });
|
||||
};
|
||||
|
||||
const { mutateAsync } = useGetOrgTrialUrl();
|
||||
@@ -239,7 +244,9 @@ export const Navbar = () => {
|
||||
|
||||
const isServerAdminPanel = location.pathname.startsWith("/admin");
|
||||
|
||||
const isOrgScope = location.pathname.startsWith("/organization"); // TODO: scott/akhil is this adequate?
|
||||
const isProjectScope =
|
||||
location.pathname.startsWith(`/organizations/${currentOrg.id}/projects`) &&
|
||||
location.pathname !== `/organizations/${currentOrg.id}/projects`;
|
||||
|
||||
const handleOrgNav = async (org: Organization) => {
|
||||
if (currentOrg?.id === org.id) return;
|
||||
@@ -269,64 +276,59 @@ export const Navbar = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="z-10 flex min-h-12 items-center bg-mineshaft-900 px-4 pt-1">
|
||||
<div className="mr-auto flex items-center overflow-hidden">
|
||||
<div className="shrink-0">
|
||||
<Link to="/organization/projects">
|
||||
<div className="z-10 flex min-h-12 items-center bg-mineshaft-900 px-4">
|
||||
<div className="mr-auto flex h-full min-w-34 items-center">
|
||||
<div className="mt-0.5 shrink-0">
|
||||
<Link to="/organizations/$orgId/projects" params={{ orgId: currentOrg.id }}>
|
||||
<img alt="infisical logo" src="/images/logotransparent.png" className="h-4" />
|
||||
</Link>
|
||||
</div>
|
||||
<p className="pr-3 pl-1 text-lg text-mineshaft-400/70">/</p>
|
||||
<ChevronRight size={18} className="mx-3 mt-[3px] text-mineshaft-400/70" />
|
||||
{isServerAdminPanel ? (
|
||||
<>
|
||||
<Link
|
||||
to="/admin"
|
||||
className="group flex cursor-pointer items-center gap-2 text-sm text-white transition-all duration-100 hover:text-primary"
|
||||
>
|
||||
<InstanceIcon className="size-3.5 text-xs text-bunker-300" />
|
||||
<div className="whitespace-nowrap">Server Console</div>
|
||||
</Link>
|
||||
<p className="pr-3 pl-3 text-lg text-mineshaft-400/70">/</p>
|
||||
{breadcrumbs ? (
|
||||
// scott: remove /admin as we show server console above
|
||||
<BreadcrumbContainer breadcrumbs={breadcrumbs.slice(1) as TBreadcrumbFormat[]} />
|
||||
) : null}
|
||||
</>
|
||||
<Link
|
||||
to="/admin"
|
||||
className="group flex cursor-pointer items-center gap-2 text-sm text-white transition-all duration-100 hover:text-primary"
|
||||
>
|
||||
<InstanceIcon className="size-3.5 text-xs text-bunker-300" />
|
||||
<div className="whitespace-nowrap">Server Console</div>
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center overflow-hidden">
|
||||
<div
|
||||
className={twMerge(
|
||||
"relative flex min-w-16 items-center self-end rounded-t-md border-x border-t pt-1.5 pr-2 pb-2.5 pl-3",
|
||||
!isProjectScope && !isSubOrganization
|
||||
? "border-org/15 bg-gradient-to-b from-org/10 to-org/[0.075]"
|
||||
: "border-transparent"
|
||||
)}
|
||||
>
|
||||
{/* scott: the below is used to hide the top border from the org nav bar */}
|
||||
{!isProjectScope && !isSubOrganization && (
|
||||
<div className="absolute -bottom-px left-0 h-px w-full bg-mineshaft-900">
|
||||
<div className="h-full bg-org/[0.075]" />
|
||||
</div>
|
||||
)}
|
||||
<DropdownMenu modal={false} open={isOrgSelectOpen} onOpenChange={setIsOrgSelectOpen}>
|
||||
<div className="group flex cursor-pointer items-center gap-2 overflow-hidden text-sm text-white transition-all duration-100 hover:text-primary">
|
||||
<Badge
|
||||
asChild
|
||||
variant="org"
|
||||
isTruncatable
|
||||
// TODO(scott): either add badge size/style variant or create designated component for namespace/org nav bar
|
||||
className={twMerge(
|
||||
"gap-x-1.5 text-sm",
|
||||
(!isOrgScope || isSubOrganization) &&
|
||||
"bg-transparent text-mineshaft-200 hover:!bg-transparent hover:underline [&>svg]:!text-org"
|
||||
)}
|
||||
<div className="group mr-1 flex min-w-0 cursor-pointer items-center gap-2 overflow-hidden text-sm text-white transition-all duration-100">
|
||||
<button
|
||||
className="flex cursor-pointer items-center gap-x-2 truncate whitespace-nowrap"
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
navigate({
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: currentOrg.id }
|
||||
});
|
||||
if (isSubOrganization) {
|
||||
await router.invalidate({ sync: true }).catch(() => null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
navigate({
|
||||
to: "/organization/projects",
|
||||
search: (search) => ({ ...search, subOrganization: undefined })
|
||||
});
|
||||
if (isSubOrganization) {
|
||||
await router.invalidate({ sync: true }).catch(() => null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<OrgIcon className="size-[12px]" />
|
||||
<span>{currentOrg?.name}</span>
|
||||
</button>
|
||||
</Badge>
|
||||
<div className="mr-1 rounded-sm border border-mineshaft-500 px-1 text-xs text-bunker-300 no-underline!">
|
||||
{getPlan(subscription)}
|
||||
</div>
|
||||
<OrgIcon className={twMerge("size-[14px] shrink-0 text-org")} />
|
||||
<span className="truncate">{currentOrg?.name}</span>
|
||||
<Badge variant="org" className="hidden lg:inline-flex">
|
||||
Organization
|
||||
</Badge>
|
||||
</button>
|
||||
{subscription.cardDeclined && (
|
||||
<Tooltip
|
||||
content={`Your payment could not be processed${subscription.cardDeclinedReason ? `: ${subscription.cardDeclinedReason}` : ""}. Please update your payment method to continue enjoying premium features.`}
|
||||
@@ -397,8 +399,8 @@ export const Navbar = () => {
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
navigate({
|
||||
to: "/organization/projects",
|
||||
search: (prev) => ({ ...prev, subOrganization: subOrg.name })
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: subOrg.id }
|
||||
});
|
||||
await router.invalidate({ sync: true }).catch(() => null);
|
||||
}}
|
||||
@@ -467,11 +469,11 @@ export const Navbar = () => {
|
||||
// TODO(scott): either add badge size/style variant or create designated component for namespace/org nav bar
|
||||
className={twMerge(
|
||||
"gap-x-1.5 text-sm",
|
||||
!isOrgScope &&
|
||||
"bg-transparent text-mineshaft-200 hover:!bg-transparent hover:underline [&>svg]:!text-sub-org"
|
||||
isProjectScope &&
|
||||
"min-w-6 bg-transparent text-mineshaft-200 hover:!bg-transparent hover:underline [&>svg]:!text-sub-org"
|
||||
)}
|
||||
>
|
||||
<Link to="/organization/projects">
|
||||
<Link to="/organizations/$orgId/projects" params={{ orgId: currentOrg.id }}>
|
||||
<SubOrgIcon className="size-[12px]" />
|
||||
<span>{currentOrg.subOrganization.name}</span>
|
||||
</Link>
|
||||
@@ -501,8 +503,8 @@ export const Navbar = () => {
|
||||
<DropdownMenuItem
|
||||
onClick={async () => {
|
||||
navigate({
|
||||
to: "/organization/projects",
|
||||
search: (prev) => ({ ...prev, subOrganization: subOrg.name })
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: subOrg.id }
|
||||
});
|
||||
await router.invalidate({ sync: true }).catch(() => null);
|
||||
}}
|
||||
@@ -531,21 +533,17 @@ export const Navbar = () => {
|
||||
</DropdownMenu>
|
||||
</>
|
||||
)}
|
||||
{!isOrgScope && (
|
||||
{isProjectScope && (
|
||||
<>
|
||||
<p className="pr-3 pl-1 text-lg text-mineshaft-400/70">/</p>
|
||||
{breadcrumbs ? (
|
||||
<BreadcrumbContainer
|
||||
className="min-w-[15rem] flex-1"
|
||||
breadcrumbs={[breadcrumbs[0]] as TBreadcrumbFormat[]}
|
||||
/>
|
||||
) : null}
|
||||
<ChevronRight size={18} className="mx-3 mt-[3px] text-mineshaft-400/70" />
|
||||
<ProjectSelect />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{subscription && subscription.slug === "starter" && !subscription.has_used_trial && (
|
||||
|
||||
{subscription && subscription.slug === "starter" && !subscription.has_used_trial ? (
|
||||
<Tooltip content="Start Free Pro Trial">
|
||||
<Button
|
||||
variant="plain"
|
||||
@@ -566,16 +564,42 @@ export const Navbar = () => {
|
||||
Free Pro Trial
|
||||
</Button>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div className="mt-0.5 mr-3 hidden rounded-sm border border-mineshaft-400 px-1 text-xs text-mineshaft-100 no-underline! opacity-50 md:inline-block">
|
||||
{getPlan(subscription)}
|
||||
</div>
|
||||
)}
|
||||
{user.superAdmin && !location.pathname.startsWith("/admin") && (
|
||||
<Link
|
||||
className="mr-2 flex items-center rounded-md border border-mineshaft-500 px-2.5 py-1.5 text-sm whitespace-nowrap text-mineshaft-200 hover:bg-mineshaft-600"
|
||||
to="/admin"
|
||||
>
|
||||
<InstanceIcon className="mr-2 inline-block size-3.5" />
|
||||
Server Console
|
||||
</Link>
|
||||
)}
|
||||
{/* eslint-disable-next-line no-nested-ternary */}
|
||||
{!location.pathname.startsWith("/admin") ? (
|
||||
user.superAdmin ? (
|
||||
<Link
|
||||
className="mr-2 flex h-[34px] items-center rounded-md border border-mineshaft-500 px-2.5 py-1.5 text-sm whitespace-nowrap text-mineshaft-200 hover:bg-mineshaft-600"
|
||||
to="/admin"
|
||||
>
|
||||
<InstanceIcon className="inline-block size-3.5" />
|
||||
<span className="ml-2 hidden md:inline-block">Server Console</span>
|
||||
</Link>
|
||||
) : (
|
||||
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
|
||||
{(isAllowed) =>
|
||||
isAllowed ? (
|
||||
<Link
|
||||
className="mr-2 flex h-[34px] items-center rounded-md border border-mineshaft-500 px-2.5 py-1.5 text-sm whitespace-nowrap text-mineshaft-200 hover:bg-mineshaft-600"
|
||||
to="/organizations/$orgId/access-management"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
search={{
|
||||
selectedTab: "members",
|
||||
action: "invite-members"
|
||||
}}
|
||||
>
|
||||
<UserPlusIcon className="inline-block size-3.5" />
|
||||
<span className="ml-2 hidden md:inline-block">Invite Users</span>
|
||||
</Link>
|
||||
) : null
|
||||
}
|
||||
</OrgPermissionCan>
|
||||
)
|
||||
) : null}
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger>
|
||||
<div className="rounded-l-md border border-r-0 border-mineshaft-500 px-2.5 py-1 hover:bg-mineshaft-600">
|
||||
@@ -657,8 +681,28 @@ export const Navbar = () => {
|
||||
</div>
|
||||
</div>
|
||||
<Link to="/personal-settings">
|
||||
<DropdownMenuItem>Personal Settings</DropdownMenuItem>
|
||||
<DropdownMenuItem icon={<FontAwesomeIcon icon={faUserCog} />}>
|
||||
Personal Settings
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
|
||||
{(isAllowed) =>
|
||||
isAllowed ? (
|
||||
<Link
|
||||
to="/organizations/$orgId/access-management"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
search={{
|
||||
selectedTab: "members",
|
||||
action: "invite-members"
|
||||
}}
|
||||
>
|
||||
<DropdownMenuItem icon={<FontAwesomeIcon icon={faUserPlus} />}>
|
||||
Invite Users
|
||||
</DropdownMenuItem>
|
||||
</Link>
|
||||
) : null
|
||||
}
|
||||
</OrgPermissionCan>
|
||||
<a
|
||||
href="https://infisical.com/docs/documentation/getting-started/introduction"
|
||||
target="_blank"
|
||||
@@ -728,7 +772,11 @@ export const Navbar = () => {
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<div className="flex space-x-3">
|
||||
<Link to="/organization/billing" className="inline-flex">
|
||||
<Link
|
||||
to="/organizations/$orgId/billing"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
className="inline-flex"
|
||||
>
|
||||
<Button
|
||||
colorSchema="primary"
|
||||
variant="solid"
|
||||
|
||||
+2
-2
@@ -47,8 +47,8 @@ export const NewSubOrganizationForm = ({ onClose }: ContentProps) => {
|
||||
onClose();
|
||||
|
||||
navigate({
|
||||
to: "/organization/projects",
|
||||
search: (prev) => ({ ...prev, subOrganization: organization.name })
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: organization.id }
|
||||
});
|
||||
await router.invalidate({ sync: true }).catch(() => null);
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
const { isRootOrganization } = useOrganization();
|
||||
const { isRootOrganization, currentOrg } = useOrganization();
|
||||
const { popUp, handlePopUpToggle } = usePopUp(["createOrg"] as const);
|
||||
|
||||
const { pathname } = useLocation();
|
||||
@@ -19,9 +19,9 @@ export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
const variant = isRootOrganization ? "org" : "namespace";
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-mineshaft-900">
|
||||
{!isHidden && (
|
||||
<div className="dark hidden w-full flex-col overflow-x-hidden border-b border-mineshaft-600 bg-mineshaft-900 px-4 md:flex">
|
||||
<div className="dark flex w-full flex-col overflow-x-hidden border-y border-t-org/15 border-b-org/5 bg-gradient-to-b from-org/[0.075] to-org/[0.025] px-4 pt-0.5">
|
||||
<motion.div
|
||||
key="menu-org-items"
|
||||
initial={{ x: -150 }}
|
||||
@@ -32,43 +32,47 @@ export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
<nav className="w-full">
|
||||
<Tabs value="selected">
|
||||
<TabList className="border-b-0">
|
||||
<Link to="/organization/projects">
|
||||
<Link to="/organizations/$orgId/projects" params={{ orgId: currentOrg.id }}>
|
||||
{({ isActive }) => (
|
||||
<Tab variant={variant} value={isActive ? "selected" : ""}>
|
||||
Overview
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link to="/organization/app-connections">
|
||||
<Link
|
||||
to="/organizations/$orgId/app-connections"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab variant={variant} value={isActive ? "selected" : ""}>
|
||||
App Connections
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link to="/organization/networking">
|
||||
<Link to="/organizations/$orgId/networking" params={{ orgId: currentOrg.id }}>
|
||||
{({ isActive }) => (
|
||||
<Tab variant={variant} value={isActive ? "selected" : ""}>
|
||||
Networking
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link to="/organization/secret-sharing">
|
||||
<Link to="/organizations/$orgId/secret-sharing" params={{ orgId: currentOrg.id }}>
|
||||
{({ isActive }) => (
|
||||
<Tab value={isActive ? "selected" : ""} variant={variant}>
|
||||
Secret Sharing
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link to="/organization/access-management">
|
||||
<Link
|
||||
to="/organizations/$orgId/access-management"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
>
|
||||
{({ isActive }) => (
|
||||
<Tab
|
||||
variant={variant}
|
||||
value={
|
||||
isActive ||
|
||||
pathname.match(
|
||||
/organization\/members|organization\/identities|organization\/groups|organization\/roles/
|
||||
)
|
||||
pathname.match(/organizations\/[^/]+\/(members|identities|groups|roles)/)
|
||||
? "selected"
|
||||
: ""
|
||||
}
|
||||
@@ -77,7 +81,7 @@ export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
</Tab>
|
||||
)}
|
||||
</Link>
|
||||
<Link to="/organization/audit-logs">
|
||||
<Link to="/organizations/$orgId/audit-logs" params={{ orgId: currentOrg.id }}>
|
||||
{({ isActive }) => (
|
||||
<Tab variant={variant} value={isActive ? "selected" : ""}>
|
||||
Audit Logs
|
||||
@@ -85,7 +89,7 @@ export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
)}
|
||||
</Link>
|
||||
{isRootOrganization && (
|
||||
<Link to="/organization/billing">
|
||||
<Link to="/organizations/$orgId/billing" params={{ orgId: currentOrg.id }}>
|
||||
{({ isActive }) => (
|
||||
<Tab variant={variant} value={isActive ? "selected" : ""}>
|
||||
Usage & Billing
|
||||
@@ -93,7 +97,7 @@ export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
)}
|
||||
</Link>
|
||||
)}
|
||||
<Link to="/organization/settings">
|
||||
<Link to="/organizations/$orgId/settings" params={{ orgId: currentOrg.id }}>
|
||||
{({ isActive }) => (
|
||||
<Tab variant={variant} value={isActive ? "selected" : ""}>
|
||||
Settings
|
||||
@@ -110,6 +114,6 @@ export const OrgNavBar = ({ isHidden }: Props) => {
|
||||
isOpen={popUp?.createOrg?.isOpen}
|
||||
onClose={() => handlePopUpToggle("createOrg", false)}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user