diff --git a/backend/e2e-test/routes/v2/secret-folder.spec.ts b/backend/e2e-test/routes/v2/secret-folder.spec.ts new file mode 100644 index 000000000..a2bed759a --- /dev/null +++ b/backend/e2e-test/routes/v2/secret-folder.spec.ts @@ -0,0 +1,165 @@ +import { seedData1 } from "@app/db/seed-data"; + +const createFolder = async (dto: { path: string; name: string }) => { + const res = await testServer.inject({ + method: "POST", + url: `/api/v2/folders`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + projectId: seedData1.project.id, + environment: seedData1.environment.slug, + name: dto.name, + path: dto.path + } + }); + expect(res.statusCode).toBe(200); + return res.json().folder; +}; + +const deleteFolder = async (dto: { path: string; id: string }) => { + const res = await testServer.inject({ + method: "DELETE", + url: `/api/v2/folders/${dto.id}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + projectId: seedData1.project.id, + environment: seedData1.environment.slug, + path: dto.path + } + }); + expect(res.statusCode).toBe(200); + return res.json().folder; +}; + +describe("Secret Folder Router", async () => { + test.each([ + { name: "folder1", path: "/" }, // one in root + { name: "folder1", path: "/level1/level2" }, // then create a deep one creating intermediate ones + { name: "folder2", path: "/" }, + { name: "folder1", path: "/level1/level2" } // this should not create folder return same thing + ])("Create folder $name in $path", async ({ name, path }) => { + const createdFolder = await createFolder({ path, name }); + // check for default environments + expect(createdFolder).toEqual( + expect.objectContaining({ + name, + id: expect.any(String) + }) + ); + await deleteFolder({ path, id: createdFolder.id }); + }); + + test.each([ + { + path: "/", + expected: { + folders: [{ name: "folder1" }, { name: "level1" }, { name: "folder2" }], + length: 3 + } + }, + { path: "/level1/level2", expected: { folders: [{ name: "folder1" }], length: 1 } } + ])("Get folders $path", async ({ path, expected }) => { + const newFolders = await Promise.all(expected.folders.map(({ name }) => createFolder({ name, path }))); + + const res = await testServer.inject({ + method: "GET", + url: `/api/v2/folders`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + query: { + projectId: seedData1.project.id, + environment: seedData1.environment.slug, + path + } + }); + + expect(res.statusCode).toBe(200); + const payload = JSON.parse(res.payload); + expect(payload).toHaveProperty("folders"); + expect(payload.folders.length >= expected.folders.length).toBeTruthy(); + expect(payload).toEqual({ + folders: expect.arrayContaining(expected.folders.map((el) => expect.objectContaining(el))) + }); + + await Promise.all(newFolders.map(({ id }) => deleteFolder({ path, id }))); + }); + + test("Update a deep folder", async () => { + const newFolder = await createFolder({ name: "folder-updated", path: "/level1/level2" }); + expect(newFolder).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: "folder-updated" + }) + ); + + const resUpdatedFolders = await testServer.inject({ + method: "GET", + url: `/api/v2/folders`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + query: { + projectId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/level1/level2" + } + }); + + expect(resUpdatedFolders.statusCode).toBe(200); + const updatedFolderList = JSON.parse(resUpdatedFolders.payload); + expect(updatedFolderList).toHaveProperty("folders"); + expect(updatedFolderList.folders[0].name).toEqual("folder-updated"); + + await deleteFolder({ path: "/level1/level2", id: newFolder.id }); + }); + + test("Delete a deep folder", async () => { + const newFolder = await createFolder({ name: "folder-updated", path: "/level1/level2" }); + const res = await testServer.inject({ + method: "DELETE", + url: `/api/v2/folders/${newFolder.id}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + projectId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/level1/level2" + } + }); + + expect(res.statusCode).toBe(200); + const payload = JSON.parse(res.payload); + expect(payload).toHaveProperty("folder"); + expect(payload.folder).toEqual( + expect.objectContaining({ + id: expect.any(String), + name: "folder-updated" + }) + ); + + const resUpdatedFolders = await testServer.inject({ + method: "GET", + url: `/api/v2/folders`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + query: { + projectId: seedData1.project.id, + environment: seedData1.environment.slug, + path: "/level1/level2" + } + }); + + expect(resUpdatedFolders.statusCode).toBe(200); + const updatedFolderList = JSON.parse(resUpdatedFolders.payload); + expect(updatedFolderList).toHaveProperty("folders"); + expect(updatedFolderList.folders.length).toEqual(0); + }); +}); diff --git a/backend/e2e-test/routes/v2/service-token.spec.ts b/backend/e2e-test/routes/v2/service-token.spec.ts index 025d9796f..4f72987cb 100644 --- a/backend/e2e-test/routes/v2/service-token.spec.ts +++ b/backend/e2e-test/routes/v2/service-token.spec.ts @@ -70,7 +70,7 @@ const createServiceToken = async ( const deleteServiceToken = async () => { const serviceTokenListRes = await testServer.inject({ method: "GET", - url: `/api/v1/workspace/${seedData1.project.id}/service-token-data`, + url: `/api/v1/projects/${seedData1.project.id}/service-token-data`, headers: { authorization: `Bearer ${jwtAuthToken}` } diff --git a/backend/e2e-test/routes/v4/secrets.spec.ts b/backend/e2e-test/routes/v4/secrets.spec.ts new file mode 100644 index 000000000..979adddf8 --- /dev/null +++ b/backend/e2e-test/routes/v4/secrets.spec.ts @@ -0,0 +1,678 @@ +import { SecretType } from "@app/db/schemas"; +import { seedData1 } from "@app/db/seed-data"; +import { AuthMode } from "@app/services/auth/auth-type"; + +type TRawSecret = { + secretKey: string; + secretValue: string; + secretComment?: string; + version: number; +}; + +const createSecret = async (dto: { path: string; key: string; value: string; comment: string; type?: SecretType }) => { + const createSecretReqBody = { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + type: dto.type || SecretType.Shared, + secretPath: dto.path, + secretKey: dto.key, + secretValue: dto.value, + secretComment: dto.comment + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v4/secrets/${dto.key}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: createSecretReqBody + }); + expect(createSecRes.statusCode).toBe(200); + const createdSecretPayload = JSON.parse(createSecRes.payload); + expect(createdSecretPayload).toHaveProperty("secret"); + return createdSecretPayload.secret as TRawSecret; +}; + +const deleteSecret = async (dto: { path: string; key: string }) => { + const deleteSecRes = await testServer.inject({ + method: "DELETE", + url: `/api/v4/secrets/${dto.key}`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + secretPath: dto.path + } + }); + expect(deleteSecRes.statusCode).toBe(200); + const updatedSecretPayload = JSON.parse(deleteSecRes.payload); + expect(updatedSecretPayload).toHaveProperty("secret"); + return updatedSecretPayload.secret as TRawSecret; +}; + +describe.each([{ auth: AuthMode.JWT }, { auth: AuthMode.IDENTITY_ACCESS_TOKEN }])( + "Secret V4 - $auth mode", + async ({ auth }) => { + let folderId = ""; + let authToken = ""; + const secretTestCases = [ + { + path: "/", + secret: { + key: "SEC1", + value: "something-secret", + comment: "some comment" + } + }, + { + path: "/nested1/nested2/folder", + secret: { + key: "NESTED-SEC1", + value: "something-secret", + comment: "some comment" + } + }, + { + path: "/", + secret: { + key: "secret-key-2", + value: `-----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCa6eeFk+cMVqFn + hoVQDYgn2Ptp5Azysr2UPq6P73pCL9BzUtOXKZROqDyGehzzfg3wE2KdYU1Jk5Uq + fP0ZOWDIlM2SaVCSI3FW32o5+ZiggjpqcVdLFc/PS0S/ZdSmpPd8h11iO2brtIAI + ugTW8fcKlGSNUwx9aFmE7A6JnTRliTxB1l6QaC+YAwTK39VgeVH2gDSWC407aS15 + QobAkaBKKmFkzB5D7i2ZJwt+uXJV/rbLmyDmtnw0lubciGn7NX9wbYef180fisqT + aPNAz0nPKk0fFH2Wd5MZixNGbrrpDA+FCYvI5doThZyT2hpj08qWP07oXXCAqw46 + IEupNSILAgMBAAECggEBAIJb5KzeaiZS3B3O8G4OBQ5rJB3WfyLYUHnoSWLsBbie + nc392/ovThLmtZAAQE6SO85Tsb93+t64Z2TKqv1H8G658UeMgfWIB78v4CcLJ2mi + TN/3opqXrzjkQOTDHzBgT7al/mpETHZ6fOdbCemK0fVALGFUioUZg4M8VXtuI4Jw + q28jAyoRKrCrzda4BeQ553NZ4G5RvwhX3O2I8B8upTbt5hLcisBKy8MPLYY5LUFj + YKAP+raf6QLliP6KYHuVxUlgzxjLTxVG41etcyqqZF+foyiKBO3PU3n8oh++tgQP + ExOxiR0JSkBG5b+oOBD0zxcvo3/SjBHn0dJOZCSU2SkCgYEAyCe676XnNyBZMRD7 + 6trsaoiCWBpA6M8H44+x3w4cQFtqV38RyLy60D+iMKjIaLqeBbnay61VMzo24Bz3 + EuF2n4+9k/MetLJ0NCw8HmN5k0WSMD2BFsJWG8glVbzaqzehP4tIclwDTYc1jQVt + IoV2/iL7HGT+x2daUwbU5kN5hK0CgYEAxiLB+fmjxJW7VY4SHDLqPdpIW0q/kv4K + d/yZBrCX799vjmFb9vLh7PkQUfJhMJ/ttJOd7EtT3xh4mfkBeLfHwVU0d/ahbmSH + UJu/E9ZGxAW3PP0kxHZtPrLKQwBnfq8AxBauIhR3rPSorQTIOKtwz1jMlHFSUpuL + 3KeK2YfDYJcCgYEAkQnJOlNcAuRb/WQzSHIvktssqK8NjiZHryy3Vc0hx7j2jES2 + HGI2dSVHYD9OSiXA0KFm3OTTsnViwm/60iGzFdjRJV6tR39xGUVcoyCuPnvRfUd0 + PYvBXgxgkYpyYlPDcwp5CvWGJy3tLi1acgOIwIuUr3S38sL//t4adGk8q1kCgYB8 + Jbs1Tl53BvrimKpwUNbE+sjrquJu0A7vL68SqgQJoQ7dP9PH4Ff/i+/V6PFM7mib + BQOm02wyFbs7fvKVGVJoqWK+6CIucX732x7W5yRgHtS5ukQXdbzt1Ek3wkEW98Cb + HTruz7RNAt/NyXlLSODeit1lBbx3Vk9EaxZtRsv88QKBgGn7JwXgez9NOyobsNIo + QVO80rpUeenSjuFi+R0VmbLKe/wgAQbYJ0xTAsQ0btqViMzB27D6mJyC+KUIwWNX + MN8a+m46v4kqvZkKL2c4gmDibyURNe/vCtCHFuanJS/1mo2tr4XDyEeiuK52eTd9 + omQDpP86RX/hIIQ+JyLSaWYa + -----END PRIVATE KEY-----`, + comment: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation" + } + }, + { + path: "/nested1/nested2/folder", + secret: { + key: "secret-key-3", + value: `-----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCa6eeFk+cMVqFn + hoVQDYgn2Ptp5Azysr2UPq6P73pCL9BzUtOXKZROqDyGehzzfg3wE2KdYU1Jk5Uq + fP0ZOWDIlM2SaVCSI3FW32o5+ZiggjpqcVdLFc/PS0S/ZdSmpPd8h11iO2brtIAI + ugTW8fcKlGSNUwx9aFmE7A6JnTRliTxB1l6QaC+YAwTK39VgeVH2gDSWC407aS15 + QobAkaBKKmFkzB5D7i2ZJwt+uXJV/rbLmyDmtnw0lubciGn7NX9wbYef180fisqT + aPNAz0nPKk0fFH2Wd5MZixNGbrrpDA+FCYvI5doThZyT2hpj08qWP07oXXCAqw46 + IEupNSILAgMBAAECggEBAIJb5KzeaiZS3B3O8G4OBQ5rJB3WfyLYUHnoSWLsBbie + nc392/ovThLmtZAAQE6SO85Tsb93+t64Z2TKqv1H8G658UeMgfWIB78v4CcLJ2mi + TN/3opqXrzjkQOTDHzBgT7al/mpETHZ6fOdbCemK0fVALGFUioUZg4M8VXtuI4Jw + q28jAyoRKrCrzda4BeQ553NZ4G5RvwhX3O2I8B8upTbt5hLcisBKy8MPLYY5LUFj + YKAP+raf6QLliP6KYHuVxUlgzxjLTxVG41etcyqqZF+foyiKBO3PU3n8oh++tgQP + ExOxiR0JSkBG5b+oOBD0zxcvo3/SjBHn0dJOZCSU2SkCgYEAyCe676XnNyBZMRD7 + 6trsaoiCWBpA6M8H44+x3w4cQFtqV38RyLy60D+iMKjIaLqeBbnay61VMzo24Bz3 + EuF2n4+9k/MetLJ0NCw8HmN5k0WSMD2BFsJWG8glVbzaqzehP4tIclwDTYc1jQVt + IoV2/iL7HGT+x2daUwbU5kN5hK0CgYEAxiLB+fmjxJW7VY4SHDLqPdpIW0q/kv4K + d/yZBrCX799vjmFb9vLh7PkQUfJhMJ/ttJOd7EtT3xh4mfkBeLfHwVU0d/ahbmSH + UJu/E9ZGxAW3PP0kxHZtPrLKQwBnfq8AxBauIhR3rPSorQTIOKtwz1jMlHFSUpuL + 3KeK2YfDYJcCgYEAkQnJOlNcAuRb/WQzSHIvktssqK8NjiZHryy3Vc0hx7j2jES2 + HGI2dSVHYD9OSiXA0KFm3OTTsnViwm/60iGzFdjRJV6tR39xGUVcoyCuPnvRfUd0 + PYvBXgxgkYpyYlPDcwp5CvWGJy3tLi1acgOIwIuUr3S38sL//t4adGk8q1kCgYB8 + Jbs1Tl53BvrimKpwUNbE+sjrquJu0A7vL68SqgQJoQ7dP9PH4Ff/i+/V6PFM7mib + BQOm02wyFbs7fvKVGVJoqWK+6CIucX732x7W5yRgHtS5ukQXdbzt1Ek3wkEW98Cb + HTruz7RNAt/NyXlLSODeit1lBbx3Vk9EaxZtRsv88QKBgGn7JwXgez9NOyobsNIo + QVO80rpUeenSjuFi+R0VmbLKe/wgAQbYJ0xTAsQ0btqViMzB27D6mJyC+KUIwWNX + MN8a+m46v4kqvZkKL2c4gmDibyURNe/vCtCHFuanJS/1mo2tr4XDyEeiuK52eTd9 + omQDpP86RX/hIIQ+JyLSaWYa + -----END PRIVATE KEY-----`, + comment: + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation" + } + }, + { + path: "/nested1/nested2/folder", + secret: { + key: "secret-key-3", + value: + "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gU2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlzIG5vc3RydWQgZXhlcmNpdGF0aW9uCg==", + comment: "" + } + } + ]; + + beforeAll(async () => { + if (auth === AuthMode.JWT) { + authToken = jwtAuthToken; + } else if (auth === AuthMode.IDENTITY_ACCESS_TOKEN) { + const identityLogin = await testServer.inject({ + method: "POST", + url: "/api/v1/auth/universal-auth/login", + body: { + clientSecret: seedData1.machineIdentity.clientCredentials.secret, + clientId: seedData1.machineIdentity.clientCredentials.id + } + }); + expect(identityLogin.statusCode).toBe(200); + authToken = identityLogin.json().accessToken; + } + // create a deep folder + const folderCreate = await testServer.inject({ + method: "POST", + url: `/api/v2/folders`, + headers: { + authorization: `Bearer ${jwtAuthToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + name: "folder", + path: "/nested1/nested2" + } + }); + expect(folderCreate.statusCode).toBe(200); + folderId = folderCreate.json().folder.id; + }); + + afterAll(async () => { + const deleteFolder = await testServer.inject({ + method: "DELETE", + url: `/api/v2/folders/${folderId}`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + path: "/nested1/nested2" + } + }); + expect(deleteFolder.statusCode).toBe(200); + }); + + const getSecrets = async (environment: string, secretPath = "/") => { + const res = await testServer.inject({ + method: "GET", + url: `/api/v4/secrets`, + headers: { + authorization: `Bearer ${authToken}` + }, + query: { + secretPath, + environment, + projectId: seedData1.projectV3.id + } + }); + const secrets: TRawSecret[] = JSON.parse(res.payload).secrets || []; + return secrets; + }; + + test.each(secretTestCases)("Create secret in path $path", async ({ secret, path }) => { + const createdSecret = await createSecret({ path, ...secret }); + expect(createdSecret.secretKey).toEqual(secret.key); + expect(createdSecret.secretValue).toEqual(secret.value); + expect(createdSecret.secretComment || "").toEqual(secret.comment); + expect(createdSecret.version).toEqual(1); + + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + secretKey: secret.key, + secretValue: secret.value, + type: SecretType.Shared + }) + ]) + ); + await deleteSecret({ path, key: secret.key }); + }); + + test.each(secretTestCases)("Get secret by name in path $path", async ({ secret, path }) => { + await createSecret({ path, ...secret }); + + const getSecByNameRes = await testServer.inject({ + method: "GET", + url: `/api/v4/secrets/${secret.key}`, + headers: { + authorization: `Bearer ${authToken}` + }, + query: { + secretPath: path, + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug + } + }); + expect(getSecByNameRes.statusCode).toBe(200); + const getSecretByNamePayload = JSON.parse(getSecByNameRes.payload); + expect(getSecretByNamePayload).toHaveProperty("secret"); + const decryptedSecret = getSecretByNamePayload.secret as TRawSecret; + expect(decryptedSecret.secretKey).toEqual(secret.key); + expect(decryptedSecret.secretValue).toEqual(secret.value); + expect(decryptedSecret.secretComment || "").toEqual(secret.comment); + + await deleteSecret({ path, key: secret.key }); + }); + + if (auth === AuthMode.JWT) { + test.each(secretTestCases)( + "Creating personal secret without shared throw error in path $path", + async ({ secret }) => { + const createSecretReqBody = { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + type: SecretType.Personal, + secretKey: secret.key, + secretValue: secret.value, + secretComment: secret.comment + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v4/secrets/SEC2`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: createSecretReqBody + }); + const payload = JSON.parse(createSecRes.payload); + expect(createSecRes.statusCode).toBe(400); + expect(payload.error).toEqual("BadRequest"); + } + ); + + test.each(secretTestCases)("Creating personal secret in path $path", async ({ secret, path }) => { + await createSecret({ path, ...secret }); + + const createSecretReqBody = { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + type: SecretType.Personal, + secretPath: path, + secretKey: secret.key, + secretValue: "personal-value", + secretComment: secret.comment + }; + const createSecRes = await testServer.inject({ + method: "POST", + url: `/api/v4/secrets/${secret.key}`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: createSecretReqBody + }); + expect(createSecRes.statusCode).toBe(200); + + // list secrets should contain personal one and shared one + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + secretKey: secret.key, + secretValue: secret.value, + type: SecretType.Shared + }), + expect.objectContaining({ + secretKey: secret.key, + secretValue: "personal-value", + type: SecretType.Personal + }) + ]) + ); + + await deleteSecret({ path, key: secret.key }); + }); + + test.each(secretTestCases)( + "Deleting personal one should not delete shared secret in path $path", + async ({ secret, path }) => { + await createSecret({ path, ...secret }); // shared one + await createSecret({ path, ...secret, type: SecretType.Personal }); + + // shared secret deletion should delete personal ones also + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + secretKey: secret.key, + type: SecretType.Shared + }), + expect.not.objectContaining({ + secretKey: secret.key, + type: SecretType.Personal + }) + ]) + ); + await deleteSecret({ path, key: secret.key }); + } + ); + } + + test.each(secretTestCases)("Update secret in path $path", async ({ path, secret }) => { + await createSecret({ path, ...secret }); + const updateSecretReqBody = { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + type: SecretType.Shared, + secretPath: path, + secretKey: secret.key, + secretValue: "new-value", + secretComment: secret.comment + }; + const updateSecRes = await testServer.inject({ + method: "PATCH", + url: `/api/v4/secrets/${secret.key}`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: updateSecretReqBody + }); + expect(updateSecRes.statusCode).toBe(200); + const updatedSecretPayload = JSON.parse(updateSecRes.payload); + expect(updatedSecretPayload).toHaveProperty("secret"); + const decryptedSecret = updatedSecretPayload.secret; + expect(decryptedSecret.secretKey).toEqual(secret.key); + expect(decryptedSecret.secretValue).toEqual("new-value"); + expect(decryptedSecret.secretComment || "").toEqual(secret.comment); + + // list secret should have updated value + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + secretKey: secret.key, + secretValue: "new-value", + type: SecretType.Shared + }) + ]) + ); + + await deleteSecret({ path, key: secret.key }); + }); + + test.each(secretTestCases)("Delete secret in path $path", async ({ secret, path }) => { + await createSecret({ path, ...secret }); + const deletedSecret = await deleteSecret({ path, key: secret.key }); + expect(deletedSecret.secretKey).toEqual(secret.key); + + // shared secret deletion should delete personal ones also + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.not.arrayContaining([ + expect.objectContaining({ + secretKey: secret.key, + type: SecretType.Shared + }), + expect.objectContaining({ + secretKey: secret.key, + type: SecretType.Personal + }) + ]) + ); + }); + + test.each(secretTestCases)("Bulk create secrets in path $path", async ({ secret, path }) => { + const createSharedSecRes = await testServer.inject({ + method: "POST", + url: `/api/v4/secrets/batch`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + secretPath: path, + secrets: Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: secret.value, + secretComment: secret.comment + })) + } + }); + expect(createSharedSecRes.statusCode).toBe(200); + const createSharedSecPayload = JSON.parse(createSharedSecRes.payload); + expect(createSharedSecPayload).toHaveProperty("secrets"); + + // bulk ones should exist + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining( + Array.from(Array(5)).map((_e, i) => + expect.objectContaining({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: secret.value, + type: SecretType.Shared + }) + ) + ) + ); + + await Promise.all( + Array.from(Array(5)).map((_e, i) => deleteSecret({ path, key: `BULK-${secret.key}-${i + 1}` })) + ); + }); + + test.each(secretTestCases)("Bulk create fail on existing secret in path $path", async ({ secret, path }) => { + await createSecret({ ...secret, key: `BULK-${secret.key}-1`, path }); + + const createSharedSecRes = await testServer.inject({ + method: "POST", + url: `/api/v4/secrets/batch`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + secretPath: path, + secrets: Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: secret.value, + secretComment: secret.comment + })) + } + }); + expect(createSharedSecRes.statusCode).toBe(400); + + await deleteSecret({ path, key: `BULK-${secret.key}-1` }); + }); + + test.each(secretTestCases)("Bulk update secrets in path $path", async ({ secret, path }) => { + await Promise.all( + Array.from(Array(5)).map((_e, i) => createSecret({ ...secret, key: `BULK-${secret.key}-${i + 1}`, path })) + ); + + const updateSharedSecRes = await testServer.inject({ + method: "PATCH", + url: `/api/v4/secrets/batch`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + secretPath: path, + secrets: Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: "update-value", + secretComment: secret.comment + })) + } + }); + expect(updateSharedSecRes.statusCode).toBe(200); + const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload); + expect(updateSharedSecPayload).toHaveProperty("secrets"); + + // bulk ones should exist + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining( + Array.from(Array(5)).map((_e, i) => + expect.objectContaining({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: "update-value", + type: SecretType.Shared + }) + ) + ) + ); + await Promise.all( + Array.from(Array(5)).map((_e, i) => deleteSecret({ path, key: `BULK-${secret.key}-${i + 1}` })) + ); + }); + + test.each(secretTestCases)("Bulk upsert secrets in path $path", async ({ secret, path }) => { + const updateSharedSecRes = await testServer.inject({ + method: "PATCH", + url: `/api/v4/secrets/batch`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + secretPath: path, + mode: "upsert", + secrets: Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: "update-value", + secretComment: secret.comment + })) + } + }); + expect(updateSharedSecRes.statusCode).toBe(200); + const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload); + expect(updateSharedSecPayload).toHaveProperty("secrets"); + + // bulk ones should exist + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.arrayContaining( + Array.from(Array(5)).map((_e, i) => + expect.objectContaining({ + secretKey: `BULK-${secret.key}-${i + 1}`, + secretValue: "update-value", + type: SecretType.Shared + }) + ) + ) + ); + await Promise.all( + Array.from(Array(5)).map((_e, i) => deleteSecret({ path, key: `BULK-${secret.key}-${i + 1}` })) + ); + }); + + test("Bulk upsert secrets in path multiple paths", async () => { + const firstBatchSecrets = Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-KEY-${secretTestCases[0].secret.key}-${i + 1}`, + secretValue: "update-value", + secretComment: "comment", + secretPath: secretTestCases[0].path + })); + const secondBatchSecrets = Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-KEY-${secretTestCases[1].secret.key}-${i + 1}`, + secretValue: "update-value", + secretComment: "comment", + secretPath: secretTestCases[1].path + })); + const testSecrets = [...firstBatchSecrets, ...secondBatchSecrets]; + + const updateSharedSecRes = await testServer.inject({ + method: "PATCH", + url: `/api/v4/secrets/batch`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + mode: "upsert", + secrets: testSecrets + } + }); + expect(updateSharedSecRes.statusCode).toBe(200); + const updateSharedSecPayload = JSON.parse(updateSharedSecRes.payload); + expect(updateSharedSecPayload).toHaveProperty("secrets"); + + // bulk ones should exist + const firstBatchSecretsOnInfisical = await getSecrets(seedData1.environment.slug, secretTestCases[0].path); + expect(firstBatchSecretsOnInfisical).toEqual( + expect.arrayContaining( + firstBatchSecrets.map((el) => + expect.objectContaining({ + secretKey: el.secretKey, + secretValue: "update-value", + type: SecretType.Shared + }) + ) + ) + ); + const secondBatchSecretsOnInfisical = await getSecrets(seedData1.environment.slug, secretTestCases[1].path); + expect(secondBatchSecretsOnInfisical).toEqual( + expect.arrayContaining( + secondBatchSecrets.map((el) => + expect.objectContaining({ + secretKey: el.secretKey, + secretValue: "update-value", + type: SecretType.Shared + }) + ) + ) + ); + await Promise.all(testSecrets.map((el) => deleteSecret({ path: el.secretPath, key: el.secretKey }))); + }); + + test.each(secretTestCases)("Bulk delete secrets in path $path", async ({ secret, path }) => { + await Promise.all( + Array.from(Array(5)).map((_e, i) => createSecret({ ...secret, key: `BULK-${secret.key}-${i + 1}`, path })) + ); + + const deletedSharedSecRes = await testServer.inject({ + method: "DELETE", + url: `/api/v4/secrets/batch`, + headers: { + authorization: `Bearer ${authToken}` + }, + body: { + projectId: seedData1.projectV3.id, + environment: seedData1.environment.slug, + secretPath: path, + secrets: Array.from(Array(5)).map((_e, i) => ({ + secretKey: `BULK-${secret.key}-${i + 1}` + })) + } + }); + + expect(deletedSharedSecRes.statusCode).toBe(200); + const deletedSecretPayload = JSON.parse(deletedSharedSecRes.payload); + expect(deletedSecretPayload).toHaveProperty("secrets"); + + // bulk ones should exist + const secrets = await getSecrets(seedData1.environment.slug, path); + expect(secrets).toEqual( + expect.not.arrayContaining( + Array.from(Array(5)).map((_e, i) => + expect.objectContaining({ + secretKey: `BULK-${secret.value}-${i + 1}`, + type: SecretType.Shared + }) + ) + ) + ); + }); + } +); diff --git a/backend/src/ee/routes/v1/audit-log-stream-routers/audit-log-stream-router.ts b/backend/src/ee/routes/v1/audit-log-stream-routers/audit-log-stream-router.ts index e0ac0b6af..48eed14c9 100644 --- a/backend/src/ee/routes/v1/audit-log-stream-routers/audit-log-stream-router.ts +++ b/backend/src/ee/routes/v1/audit-log-stream-routers/audit-log-stream-router.ts @@ -1,5 +1,9 @@ import { z } from "zod"; +import { + AzureProviderListItemSchema, + SanitizedAzureProviderSchema +} from "@app/ee/services/audit-log-stream/azure/azure-provider-schemas"; import { CriblProviderListItemSchema, SanitizedCriblProviderSchema @@ -24,6 +28,7 @@ const SanitizedAuditLogStreamSchema = z.union([ SanitizedCustomProviderSchema, SanitizedDatadogProviderSchema, SanitizedSplunkProviderSchema, + SanitizedAzureProviderSchema, SanitizedCriblProviderSchema ]); @@ -31,6 +36,7 @@ const ProviderOptionsSchema = z.discriminatedUnion("provider", [ CustomProviderListItemSchema, DatadogProviderListItemSchema, SplunkProviderListItemSchema, + AzureProviderListItemSchema, CriblProviderListItemSchema ]); diff --git a/backend/src/ee/routes/v1/audit-log-stream-routers/index.ts b/backend/src/ee/routes/v1/audit-log-stream-routers/index.ts index f40a82d89..ad338c801 100644 --- a/backend/src/ee/routes/v1/audit-log-stream-routers/index.ts +++ b/backend/src/ee/routes/v1/audit-log-stream-routers/index.ts @@ -1,4 +1,9 @@ import { LogProvider } from "@app/ee/services/audit-log-stream/audit-log-stream-enums"; +import { + CreateAzureProviderLogStreamSchema, + SanitizedAzureProviderSchema, + UpdateAzureProviderLogStreamSchema +} from "@app/ee/services/audit-log-stream/azure/azure-provider-schemas"; import { CreateCriblProviderLogStreamSchema, SanitizedCriblProviderSchema, @@ -26,6 +31,15 @@ export * from "./audit-log-stream-router"; export const AUDIT_LOG_STREAM_REGISTER_ROUTER_MAP: Record Promise> = { + [LogProvider.Azure]: async (server: FastifyZodProvider) => { + registerAuditLogStreamEndpoints({ + server, + provider: LogProvider.Azure, + sanitizedResponseSchema: SanitizedAzureProviderSchema, + createSchema: CreateAzureProviderLogStreamSchema, + updateSchema: UpdateAzureProviderLogStreamSchema + }); + }, [LogProvider.Custom]: async (server: FastifyZodProvider) => { registerAuditLogStreamEndpoints({ server, diff --git a/backend/src/ee/routes/v1/deprecated-project-role-router.ts b/backend/src/ee/routes/v1/deprecated-project-role-router.ts new file mode 100644 index 000000000..d0ffc0239 --- /dev/null +++ b/backend/src/ee/routes/v1/deprecated-project-role-router.ts @@ -0,0 +1,287 @@ +import { packRules } from "@casl/ability/extra"; +import { z } from "zod"; + +import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas"; +import { + backfillPermissionV1SchemaToV2Schema, + ProjectPermissionV1Schema +} from "@app/ee/services/permission/project-permission"; +import { PROJECT_ROLE } from "@app/lib/api-docs"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { slugSchema } from "@app/server/lib/schemas"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { SanitizedRoleSchemaV1 } from "@app/server/routes/sanitizedSchemas"; +import { AuthMode } from "@app/services/auth/auth-type"; +import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types"; + +export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "POST", + url: "/:projectSlug/roles", + config: { + rateLimit: writeLimit + }, + schema: { + description: "Create a project role", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectSlug: z.string().trim().describe(PROJECT_ROLE.CREATE.projectSlug) + }), + body: z.object({ + slug: slugSchema({ max: 64 }) + .refine( + (val) => !Object.values(ProjectMembershipRole).includes(val as ProjectMembershipRole), + "Please choose a different slug, the slug you have entered is reserved" + ) + .describe(PROJECT_ROLE.CREATE.slug), + name: z.string().min(1).trim().describe(PROJECT_ROLE.CREATE.name), + description: z.string().trim().nullish().describe(PROJECT_ROLE.CREATE.description), + permissions: ProjectPermissionV1Schema.array().describe(PROJECT_ROLE.CREATE.permissions) + }), + response: { + 200: z.object({ + role: SanitizedRoleSchemaV1 + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const role = await server.services.projectRole.createRole({ + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actor: req.permission.type, + filter: { + type: ProjectRoleServiceIdentifierType.SLUG, + projectSlug: req.params.projectSlug + }, + data: { + ...req.body, + permissions: JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) + } + }); + + return { role }; + } + }); + + server.route({ + method: "PATCH", + url: "/:projectSlug/roles/:roleId", + config: { + rateLimit: writeLimit + }, + schema: { + description: "Update a project role", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectSlug: z.string().trim().describe(PROJECT_ROLE.UPDATE.projectSlug), + roleId: z.string().trim().describe(PROJECT_ROLE.UPDATE.roleId) + }), + body: z.object({ + slug: slugSchema({ max: 64 }) + .refine( + (val) => !Object.values(ProjectMembershipRole).includes(val as ProjectMembershipRole), + "Please choose a different slug, the slug you have entered is reserved" + ) + .describe(PROJECT_ROLE.UPDATE.slug) + .optional(), + name: z.string().trim().optional().describe(PROJECT_ROLE.UPDATE.name), + description: z.string().trim().nullish().describe(PROJECT_ROLE.UPDATE.description), + permissions: ProjectPermissionV1Schema.array().describe(PROJECT_ROLE.UPDATE.permissions).optional() + }), + response: { + 200: z.object({ + role: SanitizedRoleSchemaV1 + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const role = await server.services.projectRole.updateRole({ + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actor: req.permission.type, + roleId: req.params.roleId, + data: { + ...req.body, + permissions: req.body.permissions + ? JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) + : undefined + } + }); + return { role }; + } + }); + + server.route({ + method: "DELETE", + url: "/:projectSlug/roles/:roleId", + config: { + rateLimit: writeLimit + }, + schema: { + description: "Delete a project role", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectSlug: z.string().trim().describe(PROJECT_ROLE.DELETE.projectSlug), + roleId: z.string().trim().describe(PROJECT_ROLE.DELETE.roleId) + }), + response: { + 200: z.object({ + role: SanitizedRoleSchemaV1 + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const role = await server.services.projectRole.deleteRole({ + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actor: req.permission.type, + roleId: req.params.roleId + }); + return { role }; + } + }); + + server.route({ + method: "GET", + url: "/:projectSlug/roles", + config: { + rateLimit: readLimit + }, + schema: { + description: "List project role", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectSlug: z.string().trim().describe(PROJECT_ROLE.LIST.projectSlug) + }), + response: { + 200: z.object({ + roles: ProjectRolesSchema.omit({ permissions: true, version: true }).array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const roles = await server.services.projectRole.listRoles({ + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actor: req.permission.type, + filter: { + type: ProjectRoleServiceIdentifierType.SLUG, + projectSlug: req.params.projectSlug + } + }); + return { roles }; + } + }); + + server.route({ + method: "GET", + url: "/:projectSlug/roles/slug/:slug", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + projectSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectSlug), + slug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug) + }), + response: { + 200: z.object({ + role: SanitizedRoleSchemaV1.omit({ version: true }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const role = await server.services.projectRole.getRoleBySlug({ + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actor: req.permission.type, + filter: { + type: ProjectRoleServiceIdentifierType.SLUG, + projectSlug: req.params.projectSlug + }, + roleSlug: req.params.slug + }); + + return { role }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/permissions", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + projectId: z.string().trim() + }), + response: { + 200: z.object({ + data: z.object({ + membership: z.object({ + id: z.string(), + roles: z + .object({ + role: z.string() + }) + .array() + }), + assumedPrivilegeDetails: z + .object({ + actorId: z.string(), + actorType: z.string(), + actorName: z.string(), + actorEmail: z.string().optional() + }) + .optional(), + permissions: z.any().array() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const { permissions, membership, assumedPrivilegeDetails } = await server.services.projectRole.getUserPermission( + req.permission.id, + req.params.projectId, + req.permission.authMethod, + req.permission.orgId + ); + + return { + data: { + permissions, + membership, + assumedPrivilegeDetails + } + }; + } + }); +}; diff --git a/backend/src/ee/routes/v1/deprecated-project-router.ts b/backend/src/ee/routes/v1/deprecated-project-router.ts new file mode 100644 index 000000000..6c4175f84 --- /dev/null +++ b/backend/src/ee/routes/v1/deprecated-project-router.ts @@ -0,0 +1,195 @@ +import { z } from "zod"; + +import { AuditLogsSchema, SecretSnapshotsSchema } from "@app/db/schemas"; +import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, AUDIT_LOGS, PROJECTS } from "@app/lib/api-docs"; +import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn"; +import { readLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; + +export const registerDeprecatedProjectRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "GET", + url: "/:workspaceId/secret-snapshots", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "Return project secret snapshots ids", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.projectId) + }), + querystring: z.object({ + environment: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(PROJECTS.GET_SNAPSHOTS.path), + offset: z.coerce.number().default(0).describe(PROJECTS.GET_SNAPSHOTS.offset), + limit: z.coerce.number().default(20).describe(PROJECTS.GET_SNAPSHOTS.limit) + }), + response: { + 200: z.object({ + secretSnapshots: SecretSnapshotsSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretSnapshots = await server.services.snapshot.listSnapshots({ + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + ...req.query + }); + return { secretSnapshots }; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId/secret-snapshots/count", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + workspaceId: z.string().trim() + }), + querystring: z.object({ + environment: z.string().trim(), + path: z.string().trim().default("/").transform(removeTrailingSlash) + }), + response: { + 200: z.object({ + count: z.number() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const count = await server.services.snapshot.projectSecretSnapshotCount({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + environment: req.query.environment, + path: req.query.path + }); + return { count }; + } + }); + + /* + * Daniel: This endpoint is no longer is use. + * We are keeping it for now because it has been exposed in our public api docs for a while, so by removing it we are likely to break users workflows. + * + * Please refer to the new endpoint, GET /api/v1/organization/audit-logs, for the same (and more) functionality. + */ + server.route({ + method: "GET", + url: "/:workspaceId/audit-logs", + config: { + rateLimit: readLimit + }, + schema: { + description: "Return audit logs", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(AUDIT_LOGS.EXPORT.projectId) + }), + querystring: z + .object({ + eventType: z.nativeEnum(EventType).optional().describe(AUDIT_LOGS.EXPORT.eventType), + userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType), + startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate), + endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate), + offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset), + limit: z.coerce.number().max(1000).default(20).describe(AUDIT_LOGS.EXPORT.limit), + actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor) + }) + .superRefine((el, ctx) => { + if (el.endDate && el.startDate) { + const startDate = new Date(el.startDate); + const endDate = new Date(el.endDate); + const maxAllowedDate = new Date(startDate); + maxAllowedDate.setMonth(maxAllowedDate.getMonth() + 3); + if (endDate < startDate) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["endDate"], + message: "End date cannot be before start date" + }); + } + if (endDate > maxAllowedDate) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + path: ["endDate"], + message: "Dates must be within 3 months" + }); + } + } + }), + response: { + 200: z.object({ + auditLogs: AuditLogsSchema.omit({ + eventMetadata: true, + eventType: true, + actor: true, + actorMetadata: true + }) + .merge( + z.object({ + project: z + .object({ + name: z.string(), + slug: z.string() + }) + .optional(), + event: z.object({ + type: z.string(), + metadata: z.any() + }), + actor: z.object({ + type: z.string(), + metadata: z.any() + }) + }) + ) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const auditLogs = await server.services.auditLog.listAuditLogs({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + + filter: { + ...req.query, + projectId: req.params.workspaceId, + endDate: req.query.endDate || new Date().toISOString(), + startDate: req.query.startDate || getLastMidnightDateISO(), + auditLogActorId: req.query.actor, + eventType: req.query.eventType ? [req.query.eventType] : undefined + } + }); + return { auditLogs }; + } + }); +}; diff --git a/backend/src/ee/routes/v1/deprecated-secret-approval-policy-router.ts b/backend/src/ee/routes/v1/deprecated-secret-approval-policy-router.ts new file mode 100644 index 000000000..42f6f9c12 --- /dev/null +++ b/backend/src/ee/routes/v1/deprecated-secret-approval-policy-router.ts @@ -0,0 +1,293 @@ +import { nanoid } from "nanoid"; +import { z } from "zod"; + +import { ApproverType, BypasserType } from "@app/ee/services/access-approval-policy/access-approval-policy-types"; +import { removeTrailingSlash } from "@app/lib/fn"; +import { EnforcementLevel } from "@app/lib/types"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { sapPubSchema } from "@app/server/routes/sanitizedSchemas"; +import { AuthMode } from "@app/services/auth/auth-type"; + +export const registerDeprecatedSecretApprovalPolicyRouter = async (server: FastifyZodProvider) => { + server.route({ + url: "/", + method: "POST", + config: { + rateLimit: writeLimit + }, + schema: { + body: z + .object({ + workspaceId: z.string(), + name: z.string().optional(), + environment: z.string().optional(), + environments: z.string().array().optional(), + secretPath: z + .string() + .min(1, { message: "Secret path cannot be empty" }) + .transform((val) => removeTrailingSlash(val)), + approvers: z + .discriminatedUnion("type", [ + z.object({ type: z.literal(ApproverType.Group), id: z.string() }), + z.object({ + type: z.literal(ApproverType.User), + id: z.string().optional(), + username: z.string().optional() + }) + ]) + .array() + .min(1, { message: "At least one approver should be provided" }) + .max(100, "Cannot have more than 100 approvers"), + bypassers: z + .discriminatedUnion("type", [ + z.object({ type: z.literal(BypasserType.Group), id: z.string() }), + z.object({ + type: z.literal(BypasserType.User), + id: z.string().optional(), + username: z.string().optional() + }) + ]) + .array() + .max(100, "Cannot have more than 100 bypassers") + .optional(), + approvals: z.number().min(1).default(1), + enforcementLevel: z.nativeEnum(EnforcementLevel).default(EnforcementLevel.Hard), + allowedSelfApprovals: z.boolean().default(true) + }) + .refine((data) => data.environment || data.environments, "At least one environment should be provided"), + response: { + 200: z.object({ + approval: sapPubSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const approval = await server.services.secretApprovalPolicy.createSecretApprovalPolicy({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.body.workspaceId, + ...req.body, + name: req.body.name ?? `${req.body.environment || req.body.environments?.join(",")}-${nanoid(3)}`, + enforcementLevel: req.body.enforcementLevel + }); + return { approval }; + } + }); + + server.route({ + url: "/:sapId", + method: "PATCH", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + sapId: z.string() + }), + body: z.object({ + name: z.string().optional(), + approvers: z + .discriminatedUnion("type", [ + z.object({ type: z.literal(ApproverType.Group), id: z.string() }), + z.object({ type: z.literal(ApproverType.User), id: z.string().optional(), username: z.string().optional() }) + ]) + .array() + .min(1, { message: "At least one approver should be provided" }) + .max(100, "Cannot have more than 100 approvers"), + bypassers: z + .discriminatedUnion("type", [ + z.object({ type: z.literal(BypasserType.Group), id: z.string() }), + z.object({ type: z.literal(BypasserType.User), id: z.string().optional(), username: z.string().optional() }) + ]) + .array() + .max(100, "Cannot have more than 100 bypassers") + .optional(), + approvals: z.number().min(1).default(1), + secretPath: z + .string() + .trim() + .min(1, { message: "Secret path cannot be empty" }) + .optional() + .transform((val) => (val ? removeTrailingSlash(val) : undefined)), + enforcementLevel: z.nativeEnum(EnforcementLevel).optional(), + allowedSelfApprovals: z.boolean().default(true), + environments: z.array(z.string()).optional() + }), + response: { + 200: z.object({ + approval: sapPubSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const approval = await server.services.secretApprovalPolicy.updateSecretApprovalPolicy({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body, + secretPolicyId: req.params.sapId + }); + return { approval }; + } + }); + + server.route({ + url: "/:sapId", + method: "DELETE", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + sapId: z.string() + }), + response: { + 200: z.object({ + approval: sapPubSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const approval = await server.services.secretApprovalPolicy.deleteSecretApprovalPolicy({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + secretPolicyId: req.params.sapId + }); + return { approval }; + } + }); + + server.route({ + url: "/", + method: "GET", + config: { + rateLimit: readLimit + }, + schema: { + querystring: z.object({ + workspaceId: z.string().trim() + }), + response: { + 200: z.object({ + approvals: sapPubSchema + .extend({ + approvers: z + .object({ + id: z.string().nullable().optional(), + type: z.nativeEnum(ApproverType) + }) + .array(), + bypassers: z + .object({ + id: z.string().nullable().optional(), + type: z.nativeEnum(BypasserType) + }) + .array() + }) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const approvals = await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.query.workspaceId + }); + return { approvals }; + } + }); + + server.route({ + url: "/:sapId", + method: "GET", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + sapId: z.string() + }), + response: { + 200: z.object({ + approval: sapPubSchema.extend({ + approvers: z + .object({ + id: z.string().nullable().optional(), + type: z.nativeEnum(ApproverType), + username: z.string().nullable().optional() + }) + .array(), + bypassers: z + .object({ + id: z.string().nullable().optional(), + type: z.nativeEnum(BypasserType), + username: z.string().nullable().optional() + }) + .array() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const approval = await server.services.secretApprovalPolicy.getSecretApprovalPolicyById({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.params + }); + + return { approval }; + } + }); + + server.route({ + url: "/board", + method: "GET", + config: { + rateLimit: readLimit + }, + schema: { + querystring: z.object({ + workspaceId: z.string().trim(), + environment: z.string().trim(), + secretPath: z.string().trim().transform(removeTrailingSlash) + }), + response: { + 200: z.object({ + policy: sapPubSchema + .extend({ + userApprovers: z.object({ userId: z.string().nullable().optional() }).array() + }) + .optional() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.query.workspaceId, + ...req.query + }); + return { policy }; + } + }); +}; diff --git a/backend/src/ee/routes/v1/index.ts b/backend/src/ee/routes/v1/index.ts index 5a43de381..56d450df3 100644 --- a/backend/src/ee/routes/v1/index.ts +++ b/backend/src/ee/routes/v1/index.ts @@ -5,6 +5,9 @@ import { registerAccessApprovalRequestRouter } from "./access-approval-request-r import { registerAssumePrivilegeRouter } from "./assume-privilege-router"; import { AUDIT_LOG_STREAM_REGISTER_ROUTER_MAP, registerAuditLogStreamRouter } from "./audit-log-stream-routers"; import { registerCaCrlRouter } from "./certificate-authority-crl-router"; +import { registerDeprecatedProjectRoleRouter } from "./deprecated-project-role-router"; +import { registerDeprecatedProjectRouter } from "./deprecated-project-router"; +import { registerDeprecatedSecretApprovalPolicyRouter } from "./deprecated-secret-approval-policy-router"; import { registerDynamicSecretLeaseRouter } from "./dynamic-secret-lease-router"; import { registerKubernetesDynamicSecretLeaseRouter } from "./dynamic-secret-lease-routers/kubernetes-lease-router"; import { registerDynamicSecretRouter } from "./dynamic-secret-router"; @@ -27,7 +30,6 @@ import { registerRateLimitRouter } from "./rate-limit-router"; import { registerRelayRouter } from "./relay-router"; import { registerSamlRouter } from "./saml-router"; import { registerScimRouter } from "./scim-router"; -import { registerSecretApprovalPolicyRouter } from "./secret-approval-policy-router"; import { registerSecretApprovalRequestRouter } from "./secret-approval-request-router"; import { registerSecretRotationProviderRouter } from "./secret-rotation-provider-router"; import { registerSecretRotationRouter } from "./secret-rotation-router"; @@ -47,18 +49,29 @@ export const registerV1EERoutes = async (server: FastifyZodProvider) => { // org role starts with organization await server.register(registerOrgRoleRouter, { prefix: "/organization" }); await server.register(registerLicenseRouter, { prefix: "/organizations" }); + + // depreciated in favour of infisical workspace await server.register( async (projectRouter) => { - await projectRouter.register(registerProjectRoleRouter); - await projectRouter.register(registerProjectRouter); - await projectRouter.register(registerTrustedIpRouter); - await projectRouter.register(registerAssumePrivilegeRouter); + await projectRouter.register(registerDeprecatedProjectRoleRouter); + await projectRouter.register(registerDeprecatedProjectRouter); }, { prefix: "/workspace" } ); + + await server.register( + async (projectRouter) => { + await projectRouter.register(registerProjectRoleRouter); + await projectRouter.register(registerTrustedIpRouter); + await projectRouter.register(registerAssumePrivilegeRouter); + await projectRouter.register(registerProjectRouter); + }, + { prefix: "/projects" } + ); + await server.register(registerSnapshotRouter, { prefix: "/secret-snapshot" }); await server.register(registerPITRouter, { prefix: "/pit" }); - await server.register(registerSecretApprovalPolicyRouter, { prefix: "/secret-approvals" }); + await server.register(registerDeprecatedSecretApprovalPolicyRouter, { prefix: "/secret-approvals" }); await server.register(registerSecretApprovalRequestRouter, { prefix: "/secret-approval-requests" }); diff --git a/backend/src/ee/routes/v1/project-role-router.ts b/backend/src/ee/routes/v1/project-role-router.ts index 949d4cf7e..23633c8f5 100644 --- a/backend/src/ee/routes/v1/project-role-router.ts +++ b/backend/src/ee/routes/v1/project-role-router.ts @@ -2,26 +2,26 @@ import { packRules } from "@casl/ability/extra"; import { z } from "zod"; import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas"; -import { - backfillPermissionV1SchemaToV2Schema, - ProjectPermissionV1Schema -} from "@app/ee/services/permission/project-permission"; -import { PROJECT_ROLE } from "@app/lib/api-docs"; +import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns"; +import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; +import { ApiDocsTags, PROJECT_ROLE } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; -import { SanitizedRoleSchemaV1 } from "@app/server/routes/sanitizedSchemas"; +import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas"; import { AuthMode } from "@app/services/auth/auth-type"; import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types"; export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/:projectSlug/roles", + url: "/:projectId/roles", config: { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "Create a project role", security: [ { @@ -29,10 +29,10 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - projectSlug: z.string().trim().describe(PROJECT_ROLE.CREATE.projectSlug) + projectId: z.string().trim().describe(PROJECT_ROLE.CREATE.projectId) }), body: z.object({ - slug: slugSchema({ max: 64 }) + slug: slugSchema({ min: 1, max: 64 }) .refine( (val) => !Object.values(ProjectMembershipRole).includes(val as ProjectMembershipRole), "Please choose a different slug, the slug you have entered is reserved" @@ -40,11 +40,13 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { .describe(PROJECT_ROLE.CREATE.slug), name: z.string().min(1).trim().describe(PROJECT_ROLE.CREATE.name), description: z.string().trim().nullish().describe(PROJECT_ROLE.CREATE.description), - permissions: ProjectPermissionV1Schema.array().describe(PROJECT_ROLE.CREATE.permissions) + permissions: ProjectPermissionV2Schema.array() + .describe(PROJECT_ROLE.CREATE.permissions) + .refine(checkForInvalidPermissionCombination) }), response: { 200: z.object({ - role: SanitizedRoleSchemaV1 + role: SanitizedRoleSchema }) } }, @@ -56,26 +58,27 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { actorOrgId: req.permission.orgId, actor: req.permission.type, filter: { - type: ProjectRoleServiceIdentifierType.SLUG, - projectSlug: req.params.projectSlug + type: ProjectRoleServiceIdentifierType.ID, + projectId: req.params.projectId }, data: { ...req.body, - permissions: JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) + permissions: JSON.stringify(packRules(req.body.permissions)) } }); - return { role }; } }); server.route({ method: "PATCH", - url: "/:projectSlug/roles/:roleId", + url: "/:projectId/roles/:roleId", config: { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "Update a project role", security: [ { @@ -83,24 +86,27 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - projectSlug: z.string().trim().describe(PROJECT_ROLE.UPDATE.projectSlug), + projectId: z.string().trim().describe(PROJECT_ROLE.UPDATE.projectId), roleId: z.string().trim().describe(PROJECT_ROLE.UPDATE.roleId) }), body: z.object({ - slug: slugSchema({ max: 64 }) + slug: slugSchema({ min: 1, max: 64 }) .refine( (val) => !Object.values(ProjectMembershipRole).includes(val as ProjectMembershipRole), "Please choose a different slug, the slug you have entered is reserved" ) - .describe(PROJECT_ROLE.UPDATE.slug) - .optional(), + .optional() + .describe(PROJECT_ROLE.UPDATE.slug), name: z.string().trim().optional().describe(PROJECT_ROLE.UPDATE.name), description: z.string().trim().nullish().describe(PROJECT_ROLE.UPDATE.description), - permissions: ProjectPermissionV1Schema.array().describe(PROJECT_ROLE.UPDATE.permissions).optional() + permissions: ProjectPermissionV2Schema.array() + .describe(PROJECT_ROLE.UPDATE.permissions) + .optional() + .superRefine(checkForInvalidPermissionCombination) }), response: { 200: z.object({ - role: SanitizedRoleSchemaV1 + role: SanitizedRoleSchema }) } }, @@ -114,9 +120,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { roleId: req.params.roleId, data: { ...req.body, - permissions: req.body.permissions - ? JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) - : undefined + permissions: req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined } }); return { role }; @@ -125,11 +129,13 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { server.route({ method: "DELETE", - url: "/:projectSlug/roles/:roleId", + url: "/:projectId/roles/:roleId", config: { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "Delete a project role", security: [ { @@ -137,12 +143,12 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - projectSlug: z.string().trim().describe(PROJECT_ROLE.DELETE.projectSlug), + projectId: z.string().trim().describe(PROJECT_ROLE.DELETE.projectId), roleId: z.string().trim().describe(PROJECT_ROLE.DELETE.roleId) }), response: { 200: z.object({ - role: SanitizedRoleSchemaV1 + role: SanitizedRoleSchema }) } }, @@ -161,11 +167,13 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:projectSlug/roles", + url: "/:projectId/roles", config: { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "List project role", security: [ { @@ -173,7 +181,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - projectSlug: z.string().trim().describe(PROJECT_ROLE.LIST.projectSlug) + projectId: z.string().trim().describe(PROJECT_ROLE.LIST.projectId) }), response: { 200: z.object({ @@ -189,8 +197,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { actorOrgId: req.permission.orgId, actor: req.permission.type, filter: { - type: ProjectRoleServiceIdentifierType.SLUG, - projectSlug: req.params.projectSlug + type: ProjectRoleServiceIdentifierType.ID, + projectId: req.params.projectId } }); return { roles }; @@ -199,18 +207,20 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:projectSlug/roles/slug/:slug", + url: "/:projectId/roles/slug/:roleSlug", config: { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], params: z.object({ - projectSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectSlug), - slug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug) + projectId: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectId), + roleSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug) }), response: { 200: z.object({ - role: SanitizedRoleSchemaV1.omit({ version: true }) + role: SanitizedRoleSchema.omit({ version: true }) }) } }, @@ -222,12 +232,11 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { actorOrgId: req.permission.orgId, actor: req.permission.type, filter: { - type: ProjectRoleServiceIdentifierType.SLUG, - projectSlug: req.params.projectSlug + type: ProjectRoleServiceIdentifierType.ID, + projectId: req.params.projectId }, - roleSlug: req.params.slug + roleSlug: req.params.roleSlug }); - return { role }; } }); diff --git a/backend/src/ee/routes/v1/project-router.ts b/backend/src/ee/routes/v1/project-router.ts index 8d8cc4817..4988565f8 100644 --- a/backend/src/ee/routes/v1/project-router.ts +++ b/backend/src/ee/routes/v1/project-router.ts @@ -1,9 +1,9 @@ import { z } from "zod"; -import { AuditLogsSchema, SecretSnapshotsSchema } from "@app/db/schemas"; -import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; -import { ApiDocsTags, AUDIT_LOGS, PROJECTS } from "@app/lib/api-docs"; -import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn"; +import { SecretSnapshotsSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; +import { removeTrailingSlash } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -12,7 +12,7 @@ import { KmsType } from "@app/services/kms/kms-types"; export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/secret-snapshots", + url: "/:projectId/secret-snapshots", config: { rateLimit: readLimit }, @@ -26,7 +26,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.workspaceId) + projectId: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.projectId) }), querystring: z.object({ environment: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.environment), @@ -47,7 +47,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, ...req.query }); return { secretSnapshots }; @@ -56,13 +56,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/secret-snapshots/count", + url: "/:projectId/secret-snapshots/count", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), querystring: z.object({ environment: z.string().trim(), @@ -81,7 +81,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, environment: req.query.environment, path: req.query.path }); @@ -89,140 +89,15 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } }); - /* - * Daniel: This endpoint is no longer is use. - * We are keeping it for now because it has been exposed in our public api docs for a while, so by removing it we are likely to break users workflows. - * - * Please refer to the new endpoint, GET /api/v1/organization/audit-logs, for the same (and more) functionality. - */ server.route({ method: "GET", - url: "/:workspaceId/audit-logs", - config: { - rateLimit: readLimit - }, - schema: { - description: "Return audit logs", - security: [ - { - bearerAuth: [] - } - ], - params: z.object({ - workspaceId: z.string().trim().describe(AUDIT_LOGS.EXPORT.projectId) - }), - querystring: z - .object({ - eventType: z.nativeEnum(EventType).optional().describe(AUDIT_LOGS.EXPORT.eventType), - userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType), - startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate), - endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate), - offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset), - limit: z.coerce.number().max(1000).default(20).describe(AUDIT_LOGS.EXPORT.limit), - actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor) - }) - .superRefine((el, ctx) => { - if (el.endDate && el.startDate) { - const startDate = new Date(el.startDate); - const endDate = new Date(el.endDate); - const maxAllowedDate = new Date(startDate); - maxAllowedDate.setMonth(maxAllowedDate.getMonth() + 3); - if (endDate < startDate) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ["endDate"], - message: "End date cannot be before start date" - }); - } - if (endDate > maxAllowedDate) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - path: ["endDate"], - message: "Dates must be within 3 months" - }); - } - } - }), - response: { - 200: z.object({ - auditLogs: AuditLogsSchema.omit({ - eventMetadata: true, - eventType: true, - actor: true, - actorMetadata: true - }) - .merge( - z.object({ - project: z - .object({ - name: z.string(), - slug: z.string() - }) - .optional(), - event: z.object({ - type: z.string(), - metadata: z.any() - }), - actor: z.object({ - type: z.string(), - metadata: z.any() - }) - }) - ) - .array() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), - handler: async (req) => { - const auditLogs = await server.services.auditLog.listAuditLogs({ - actorId: req.permission.id, - actorOrgId: req.permission.orgId, - actorAuthMethod: req.permission.authMethod, - actor: req.permission.type, - - filter: { - ...req.query, - projectId: req.params.workspaceId, - endDate: req.query.endDate || new Date().toISOString(), - startDate: req.query.startDate || getLastMidnightDateISO(), - auditLogActorId: req.query.actor, - eventType: req.query.eventType ? [req.query.eventType] : undefined - } - }); - return { auditLogs }; - } - }); - - server.route({ - method: "GET", - url: "/:workspaceId/audit-logs/filters/actors", + url: "/:projectId/kms", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() - }), - response: { - 200: z.object({ - actors: z.string().array() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async () => ({ actors: [] }) - }); - - server.route({ - method: "GET", - url: "/:workspaceId/kms", - config: { - rateLimit: readLimit - }, - schema: { - params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -241,7 +116,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return kmsKey; @@ -250,13 +125,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "PATCH", - url: "/:workspaceId/kms", + url: "/:projectId/kms", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), body: z.object({ kms: z.discriminatedUnion("type", [ @@ -281,13 +156,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, ...req.body }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.UPDATE_PROJECT_KMS, metadata: { @@ -307,13 +182,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/kms/backup", + url: "/:projectId/kms/backup", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -328,12 +203,12 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.GET_PROJECT_KMS_BACKUP, metadata: {} @@ -346,13 +221,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/:workspaceId/kms/backup", + url: "/:projectId/kms/backup", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), body: z.object({ backup: z.string().min(1) @@ -374,13 +249,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, backup: req.body.backup }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.LOAD_PROJECT_KMS_BACKUP, metadata: {} @@ -393,13 +268,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/:workspaceId/migrate-v3", + url: "/:projectId/migrate-v3", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { @@ -415,7 +290,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return migration; diff --git a/backend/src/ee/routes/v1/secret-approval-request-router.ts b/backend/src/ee/routes/v1/secret-approval-request-router.ts index bdc9c2dcd..6a9b59f00 100644 --- a/backend/src/ee/routes/v1/secret-approval-request-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-request-router.ts @@ -27,7 +27,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv }, schema: { querystring: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), environment: z.string().trim().optional(), committer: z.string().trim().optional(), search: z.string().trim().optional(), @@ -80,7 +80,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.query, - projectId: req.query.workspaceId + projectId: req.query.projectId }); return { approvals, totalCount }; } @@ -94,7 +94,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv }, schema: { querystring: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), policyId: z.string().trim().optional() }), response: { @@ -113,7 +113,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.query.workspaceId, + projectId: req.query.projectId, policyId: req.query.policyId }); return { approvals }; diff --git a/backend/src/ee/routes/v1/trusted-ip-router.ts b/backend/src/ee/routes/v1/trusted-ip-router.ts index b6fc3cc90..5416e8613 100644 --- a/backend/src/ee/routes/v1/trusted-ip-router.ts +++ b/backend/src/ee/routes/v1/trusted-ip-router.ts @@ -9,13 +9,13 @@ import { AuthMode } from "@app/services/auth/auth-type"; export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/trusted-ips", + url: "/:projectId/trusted-ips", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -27,7 +27,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { handler: async (req) => { const trustedIps = await server.services.trustedIp.listIpsByProjectId({ actorAuthMethod: req.permission.authMethod, - projectId: req.params.workspaceId, + projectId: req.params.projectId, actor: req.permission.type, actorId: req.permission.id, actorOrgId: req.permission.orgId @@ -38,13 +38,13 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/:workspaceId/trusted-ips", + url: "/:projectId/trusted-ips", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), body: z.object({ ipAddress: z.string().trim(), @@ -61,7 +61,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { handler: async (req) => { const { trustedIp, project } = await server.services.trustedIp.addProjectIp({ actorAuthMethod: req.permission.authMethod, - projectId: req.params.workspaceId, + projectId: req.params.projectId, actor: req.permission.type, actorId: req.permission.id, actorOrgId: req.permission.orgId, @@ -86,13 +86,13 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { server.route({ method: "PATCH", - url: "/:workspaceId/trusted-ips/:trustedIpId", + url: "/:projectId/trusted-ips/:trustedIpId", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), trustedIpId: z.string().trim() }), body: z.object({ @@ -108,7 +108,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { const { trustedIp, project } = await server.services.trustedIp.updateProjectIp({ - projectId: req.params.workspaceId, + projectId: req.params.projectId, actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -135,13 +135,13 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { server.route({ method: "DELETE", - url: "/:workspaceId/trusted-ips/:trustedIpId", + url: "/:projectId/trusted-ips/:trustedIpId", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), trustedIpId: z.string().trim() }), response: { @@ -153,7 +153,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => { onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { const { trustedIp, project } = await server.services.trustedIp.deleteProjectIp({ - projectId: req.params.workspaceId, + projectId: req.params.projectId, actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, diff --git a/backend/src/ee/routes/v2/project-role-router.ts b/backend/src/ee/routes/v2/deprecated-project-role-router.ts similarity index 98% rename from backend/src/ee/routes/v2/project-role-router.ts rename to backend/src/ee/routes/v2/deprecated-project-role-router.ts index 538929316..41a04974d 100644 --- a/backend/src/ee/routes/v2/project-role-router.ts +++ b/backend/src/ee/routes/v2/deprecated-project-role-router.ts @@ -12,7 +12,7 @@ import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas"; import { AuthMode } from "@app/services/auth/auth-type"; import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types"; -export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { +export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", url: "/:projectId/roles", diff --git a/backend/src/ee/routes/v2/index.ts b/backend/src/ee/routes/v2/index.ts index e082773dd..c402ab00a 100644 --- a/backend/src/ee/routes/v2/index.ts +++ b/backend/src/ee/routes/v2/index.ts @@ -7,15 +7,16 @@ import { SECRET_SCANNING_REGISTER_ROUTER_MAP } from "@app/ee/routes/v2/secret-scanning-v2-routers"; +import { registerDeprecatedProjectRoleRouter } from "./deprecated-project-role-router"; import { registerGatewayV2Router } from "./gateway-router"; import { registerIdentityProjectAdditionalPrivilegeRouter } from "./identity-project-additional-privilege-router"; -import { registerProjectRoleRouter } from "./project-role-router"; +import { registerSecretApprovalPolicyRouter } from "./secret-approval-policy-router"; export const registerV2EERoutes = async (server: FastifyZodProvider) => { - // org role starts with organization await server.register( async (projectRouter) => { - await projectRouter.register(registerProjectRoleRouter); + // this has been depreciated and moved to /api/v1/projects + await projectRouter.register(registerDeprecatedProjectRoleRouter); }, { prefix: "/workspace" } ); @@ -26,6 +27,8 @@ export const registerV2EERoutes = async (server: FastifyZodProvider) => { await server.register(registerGatewayV2Router, { prefix: "/gateways" }); + await server.register(registerSecretApprovalPolicyRouter, { prefix: "/secret-approvals" }); + await server.register( async (secretRotationV2Router) => { // register generic secret rotation endpoints diff --git a/backend/src/ee/routes/v1/secret-approval-policy-router.ts b/backend/src/ee/routes/v2/secret-approval-policy-router.ts similarity index 97% rename from backend/src/ee/routes/v1/secret-approval-policy-router.ts rename to backend/src/ee/routes/v2/secret-approval-policy-router.ts index dc87b83f2..f7f770197 100644 --- a/backend/src/ee/routes/v1/secret-approval-policy-router.ts +++ b/backend/src/ee/routes/v2/secret-approval-policy-router.ts @@ -19,7 +19,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi schema: { body: z .object({ - workspaceId: z.string(), + projectId: z.string(), name: z.string().optional(), environment: z.string().optional(), environments: z.string().array().optional(), @@ -69,7 +69,6 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.body.workspaceId, ...req.body, name: req.body.name ?? `${req.body.environment || req.body.environments?.join(",")}-${nanoid(3)}`, enforcementLevel: req.body.enforcementLevel @@ -174,7 +173,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }, schema: { querystring: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -204,7 +203,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.query.workspaceId + projectId: req.query.projectId }); return { approvals }; } @@ -263,7 +262,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }, schema: { querystring: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), environment: z.string().trim(), secretPath: z.string().trim().transform(removeTrailingSlash) }), @@ -284,7 +283,6 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.query.workspaceId, ...req.query }); return { policy }; diff --git a/backend/src/ee/services/audit-log-stream/audit-log-stream-enums.ts b/backend/src/ee/services/audit-log-stream/audit-log-stream-enums.ts index 78233f774..ebef18574 100644 --- a/backend/src/ee/services/audit-log-stream/audit-log-stream-enums.ts +++ b/backend/src/ee/services/audit-log-stream/audit-log-stream-enums.ts @@ -1,4 +1,5 @@ export enum LogProvider { + Azure = "azure", Cribl = "cribl", Custom = "custom", Datadog = "datadog", diff --git a/backend/src/ee/services/audit-log-stream/audit-log-stream-factory.ts b/backend/src/ee/services/audit-log-stream/audit-log-stream-factory.ts index 21d629a53..8dde0e079 100644 --- a/backend/src/ee/services/audit-log-stream/audit-log-stream-factory.ts +++ b/backend/src/ee/services/audit-log-stream/audit-log-stream-factory.ts @@ -1,5 +1,6 @@ import { LogProvider } from "./audit-log-stream-enums"; import { TAuditLogStreamCredentials, TLogStreamFactory } from "./audit-log-stream-types"; +import { AzureProviderFactory } from "./azure/azure-provider-factory"; import { CriblProviderFactory } from "./cribl/cribl-provider-factory"; import { CustomProviderFactory } from "./custom/custom-provider-factory"; import { DatadogProviderFactory } from "./datadog/datadog-provider-factory"; @@ -8,6 +9,7 @@ import { SplunkProviderFactory } from "./splunk/splunk-provider-factory"; type TLogStreamFactoryImplementation = TLogStreamFactory; export const LOG_STREAM_FACTORY_MAP: Record = { + [LogProvider.Azure]: AzureProviderFactory as TLogStreamFactoryImplementation, [LogProvider.Datadog]: DatadogProviderFactory as TLogStreamFactoryImplementation, [LogProvider.Splunk]: SplunkProviderFactory as TLogStreamFactoryImplementation, [LogProvider.Custom]: CustomProviderFactory as TLogStreamFactoryImplementation, diff --git a/backend/src/ee/services/audit-log-stream/audit-log-stream-fns.ts b/backend/src/ee/services/audit-log-stream/audit-log-stream-fns.ts index d03a5c8a7..07d833030 100644 --- a/backend/src/ee/services/audit-log-stream/audit-log-stream-fns.ts +++ b/backend/src/ee/services/audit-log-stream/audit-log-stream-fns.ts @@ -3,6 +3,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { KmsDataKey } from "@app/services/kms/kms-types"; import { TAuditLogStream, TAuditLogStreamCredentials } from "./audit-log-stream-types"; +import { getAzureProviderListItem } from "./azure/azure-provider-fns"; import { getCriblProviderListItem } from "./cribl/cribl-provider-fns"; import { getCustomProviderListItem } from "./custom/custom-provider-fns"; import { getDatadogProviderListItem } from "./datadog/datadog-provider-fns"; @@ -13,6 +14,7 @@ export const listProviderOptions = () => { getDatadogProviderListItem(), getSplunkProviderListItem(), getCustomProviderListItem(), + getAzureProviderListItem(), getCriblProviderListItem() ].sort((a, b) => a.name.localeCompare(b.name)); }; diff --git a/backend/src/ee/services/audit-log-stream/audit-log-stream-types.ts b/backend/src/ee/services/audit-log-stream/audit-log-stream-types.ts index 1ef33befe..5983e50bf 100644 --- a/backend/src/ee/services/audit-log-stream/audit-log-stream-types.ts +++ b/backend/src/ee/services/audit-log-stream/audit-log-stream-types.ts @@ -1,17 +1,19 @@ import { TAuditLogs } from "@app/db/schemas"; import { LogProvider } from "./audit-log-stream-enums"; +import { TAzureProvider, TAzureProviderCredentials } from "./azure/azure-provider-types"; import { TCriblProvider, TCriblProviderCredentials } from "./cribl/cribl-provider-types"; import { TCustomProvider, TCustomProviderCredentials } from "./custom/custom-provider-types"; import { TDatadogProvider, TDatadogProviderCredentials } from "./datadog/datadog-provider-types"; import { TSplunkProvider, TSplunkProviderCredentials } from "./splunk/splunk-provider-types"; -export type TAuditLogStream = TDatadogProvider | TSplunkProvider | TCustomProvider | TCriblProvider; +export type TAuditLogStream = TDatadogProvider | TSplunkProvider | TCustomProvider | TAzureProvider | TCriblProvider; export type TAuditLogStreamCredentials = | TDatadogProviderCredentials | TSplunkProviderCredentials | TCustomProviderCredentials + | TAzureProviderCredentials | TCriblProviderCredentials; export type TCreateAuditLogStreamDTO = { diff --git a/backend/src/ee/services/audit-log-stream/azure/azure-provider-factory.ts b/backend/src/ee/services/audit-log-stream/azure/azure-provider-factory.ts new file mode 100644 index 000000000..9a6157666 --- /dev/null +++ b/backend/src/ee/services/audit-log-stream/azure/azure-provider-factory.ts @@ -0,0 +1,98 @@ +import { RawAxiosRequestHeaders } from "axios"; + +import { request } from "@app/lib/config/request"; +import { BadRequestError } from "@app/lib/errors"; +import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; + +import { AUDIT_LOG_STREAM_TIMEOUT } from "../../audit-log/audit-log-queue"; +import { TLogStreamFactoryStreamLog, TLogStreamFactoryValidateCredentials } from "../audit-log-stream-types"; +import { TAzureProviderCredentials } from "./azure-provider-types"; + +function createPayload(event: { createdAt?: Date | string } & Record) { + return [ + { + ...event, + TimeGenerated: (event.createdAt ? new Date(event.createdAt) : new Date()).toISOString() + } + ]; +} + +async function getAzureToken(tenantId: string, clientId: string, clientSecret: string) { + const { data } = await request.post<{ access_token: string }>( + `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, + new URLSearchParams({ + grant_type: "client_credentials", + client_id: clientId, + client_secret: clientSecret, + scope: "https://monitor.azure.com/.default" + }), + { + headers: { + "Content-Type": "application/x-www-form-urlencoded" + } + } + ); + + return data.access_token; +} + +export const AzureProviderFactory = () => { + const validateCredentials: TLogStreamFactoryValidateCredentials = async ({ + credentials + }) => { + const { tenantId, clientId, clientSecret, dceUrl, dcrId, cltName } = credentials; + + await blockLocalAndPrivateIpAddresses(dceUrl); + + const token = await getAzureToken(tenantId, clientId, clientSecret); + + const streamHeaders: RawAxiosRequestHeaders = { + "Content-Type": "application/json", + Authorization: `Bearer ${token}` + }; + + await request + .post( + `${dceUrl}/dataCollectionRules/${dcrId}/streams/Custom-${cltName}_CL?api-version=2023-01-01`, + createPayload({ ping: "ok" }), + { + headers: streamHeaders, + timeout: AUDIT_LOG_STREAM_TIMEOUT, + signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT) + } + ) + .catch((err) => { + throw new BadRequestError({ message: `Failed to connect with Azure: ${(err as Error)?.message}` }); + }); + + return credentials; + }; + + const streamLog: TLogStreamFactoryStreamLog = async ({ credentials, auditLog }) => { + const { tenantId, clientId, clientSecret, dceUrl, dcrId, cltName } = credentials; + + await blockLocalAndPrivateIpAddresses(dceUrl); + + const token = await getAzureToken(tenantId, clientId, clientSecret); + + const streamHeaders: RawAxiosRequestHeaders = { + "Content-Type": "application/json", + Authorization: `Bearer ${token}` + }; + + await request.post( + `${dceUrl}/dataCollectionRules/${dcrId}/streams/Custom-${cltName}_CL?api-version=2023-01-01`, + createPayload(auditLog), + { + headers: streamHeaders, + timeout: AUDIT_LOG_STREAM_TIMEOUT, + signal: AbortSignal.timeout(AUDIT_LOG_STREAM_TIMEOUT) + } + ); + }; + + return { + validateCredentials, + streamLog + }; +}; diff --git a/backend/src/ee/services/audit-log-stream/azure/azure-provider-fns.ts b/backend/src/ee/services/audit-log-stream/azure/azure-provider-fns.ts new file mode 100644 index 000000000..e558b69e2 --- /dev/null +++ b/backend/src/ee/services/audit-log-stream/azure/azure-provider-fns.ts @@ -0,0 +1,8 @@ +import { LogProvider } from "../audit-log-stream-enums"; + +export const getAzureProviderListItem = () => { + return { + name: "Azure" as const, + provider: LogProvider.Azure as const + }; +}; diff --git a/backend/src/ee/services/audit-log-stream/azure/azure-provider-schemas.ts b/backend/src/ee/services/audit-log-stream/azure/azure-provider-schemas.ts new file mode 100644 index 000000000..50def1d79 --- /dev/null +++ b/backend/src/ee/services/audit-log-stream/azure/azure-provider-schemas.ts @@ -0,0 +1,52 @@ +import RE2 from "re2"; +import { z } from "zod"; + +import { LogProvider } from "../audit-log-stream-enums"; +import { BaseProviderSchema } from "../audit-log-stream-schemas"; + +export const AzureProviderCredentialsSchema = z.object({ + tenantId: z.string().trim().uuid(), + clientId: z.string().trim().uuid(), + clientSecret: z.string().trim().length(40), + + // Data Collection Endpoint URL + dceUrl: z.string().trim().url().min(1).max(255), + + // Data Collection Rule Immutable ID + dcrId: z + .string() + .trim() + .refine((val) => new RE2(/^dcr-[0-9a-f]{32}$/).test(val), "DCR ID must be in dcr-*** format"), + + // Custom Log Table Name + cltName: z.string().trim().min(1).max(255) +}); + +const BaseAzureProviderSchema = BaseProviderSchema.extend({ provider: z.literal(LogProvider.Azure) }); + +export const AzureProviderSchema = BaseAzureProviderSchema.extend({ + credentials: AzureProviderCredentialsSchema +}); + +export const SanitizedAzureProviderSchema = BaseAzureProviderSchema.extend({ + credentials: AzureProviderCredentialsSchema.pick({ + tenantId: true, + clientId: true, + dceUrl: true, + dcrId: true, + cltName: true + }) +}); + +export const AzureProviderListItemSchema = z.object({ + name: z.literal("Azure"), + provider: z.literal(LogProvider.Azure) +}); + +export const CreateAzureProviderLogStreamSchema = z.object({ + credentials: AzureProviderCredentialsSchema +}); + +export const UpdateAzureProviderLogStreamSchema = z.object({ + credentials: AzureProviderCredentialsSchema +}); diff --git a/backend/src/ee/services/audit-log-stream/azure/azure-provider-types.ts b/backend/src/ee/services/audit-log-stream/azure/azure-provider-types.ts new file mode 100644 index 000000000..0ba5f120d --- /dev/null +++ b/backend/src/ee/services/audit-log-stream/azure/azure-provider-types.ts @@ -0,0 +1,7 @@ +import { z } from "zod"; + +import { AzureProviderCredentialsSchema, AzureProviderSchema } from "./azure-provider-schemas"; + +export type TAzureProvider = z.infer; + +export type TAzureProviderCredentials = z.infer; diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 88b4480bc..3e2190b65 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -146,7 +146,7 @@ export enum EventType { MOVE_SECRETS = "move-secrets", DELETE_SECRET = "delete-secret", DELETE_SECRETS = "delete-secrets", - GET_WORKSPACE_KEY = "get-workspace-key", + GET_PROJECT_KEY = "get-project-key", AUTHORIZE_INTEGRATION = "authorize-integration", UPDATE_INTEGRATION_AUTH = "update-integration-auth", UNAUTHORIZE_INTEGRATION = "unauthorize-integration", @@ -249,9 +249,9 @@ export enum EventType { UPDATE_ENVIRONMENT = "update-environment", DELETE_ENVIRONMENT = "delete-environment", GET_ENVIRONMENT = "get-environment", - ADD_WORKSPACE_MEMBER = "add-workspace-member", - ADD_BATCH_WORKSPACE_MEMBER = "add-workspace-members", - REMOVE_WORKSPACE_MEMBER = "remove-workspace-member", + ADD_PROJECT_MEMBER = "add-project-member", + ADD_BATCH_PROJECT_MEMBER = "add-project-members", + REMOVE_PROJECT_MEMBER = "remove-project-member", CREATE_FOLDER = "create-folder", UPDATE_FOLDER = "update-folder", DELETE_FOLDER = "delete-folder", @@ -264,8 +264,8 @@ export enum EventType { CREATE_SECRET_IMPORT = "create-secret-import", UPDATE_SECRET_IMPORT = "update-secret-import", DELETE_SECRET_IMPORT = "delete-secret-import", - UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role", - UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions", + UPDATE_USER_PROJECT_ROLE = "update-user-project-role", + UPDATE_USER_PROJECT_DENIED_PERMISSIONS = "update-user-project-denied-permissions", SECRET_APPROVAL_MERGED = "secret-approval-merged", SECRET_APPROVAL_REQUEST = "secret-approval-request", SECRET_APPROVAL_CLOSED = "secret-approval-closed", @@ -666,8 +666,8 @@ interface DeleteSecretBatchEvent { }; } -interface GetWorkspaceKeyEvent { - type: EventType.GET_WORKSPACE_KEY; +interface GetProjectKeyEvent { + type: EventType.GET_PROJECT_KEY; metadata: { keyId: string; }; @@ -1559,24 +1559,24 @@ interface DeleteEnvironmentEvent { }; } -interface AddWorkspaceMemberEvent { - type: EventType.ADD_WORKSPACE_MEMBER; +interface AddProjectMemberEvent { + type: EventType.ADD_PROJECT_MEMBER; metadata: { userId: string; email: string; }; } -interface AddBatchWorkspaceMemberEvent { - type: EventType.ADD_BATCH_WORKSPACE_MEMBER; +interface AddBatchProjectMemberEvent { + type: EventType.ADD_BATCH_PROJECT_MEMBER; metadata: Array<{ userId: string; email: string; }>; } -interface RemoveWorkspaceMemberEvent { - type: EventType.REMOVE_WORKSPACE_MEMBER; +interface RemoveProjectMemberEvent { + type: EventType.REMOVE_PROJECT_MEMBER; metadata: { userId: string; email: string; @@ -1715,7 +1715,7 @@ interface DeleteSecretImportEvent { } interface UpdateUserRole { - type: EventType.UPDATE_USER_WORKSPACE_ROLE; + type: EventType.UPDATE_USER_PROJECT_ROLE; metadata: { userId: string; email: string; @@ -1725,7 +1725,7 @@ interface UpdateUserRole { } interface UpdateUserDeniedPermissions { - type: EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS; + type: EventType.UPDATE_USER_PROJECT_DENIED_PERMISSIONS; metadata: { userId: string; email: string; @@ -3496,7 +3496,7 @@ export type Event = | MoveSecretsEvent | DeleteSecretEvent | DeleteSecretBatchEvent - | GetWorkspaceKeyEvent + | GetProjectKeyEvent | AuthorizeIntegrationEvent | UpdateIntegrationAuthEvent | UnauthorizeIntegrationEvent @@ -3585,9 +3585,9 @@ export type Event = | GetEnvironmentEvent | UpdateEnvironmentEvent | DeleteEnvironmentEvent - | AddWorkspaceMemberEvent - | AddBatchWorkspaceMemberEvent - | RemoveWorkspaceMemberEvent + | AddProjectMemberEvent + | AddBatchProjectMemberEvent + | RemoveProjectMemberEvent | CreateFolderEvent | UpdateFolderEvent | DeleteFolderEvent diff --git a/backend/src/ee/services/permission/org-permission.ts b/backend/src/ee/services/permission/org-permission.ts index d4155d02c..89a518032 100644 --- a/backend/src/ee/services/permission/org-permission.ts +++ b/backend/src/ee/services/permission/org-permission.ts @@ -87,6 +87,7 @@ export enum OrgPermissionBillingActions { export enum OrgPermissionSubjects { Workspace = "workspace", + Project = "project", Role = "role", Member = "member", Settings = "settings", @@ -117,6 +118,7 @@ export type AppConnectionSubjectFields = { export type OrgPermissionSet = | [OrgPermissionActions.Create, OrgPermissionSubjects.Workspace] + | [OrgPermissionActions.Create, OrgPermissionSubjects.Project] | [OrgPermissionActions, OrgPermissionSubjects.Role] | [OrgPermissionActions, OrgPermissionSubjects.Member] | [OrgPermissionActions, OrgPermissionSubjects.Settings] @@ -166,6 +168,10 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [ subject: z.literal(OrgPermissionSubjects.Workspace).describe("The entity this permission pertains to."), action: CASL_ACTION_SCHEMA_ENUM([OrgPermissionActions.Create]).describe("Describe what action an entity can take.") }), + z.object({ + subject: z.literal(OrgPermissionSubjects.Project).describe("The entity this permission pertains to."), + action: CASL_ACTION_SCHEMA_ENUM([OrgPermissionActions.Create]).describe("Describe what action an entity can take.") + }), z.object({ subject: z.literal(OrgPermissionSubjects.Role).describe("The entity this permission pertains to."), action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.") @@ -280,6 +286,7 @@ const buildAdminPermission = () => { const { can, rules } = new AbilityBuilder>(createMongoAbility); // ws permissions can(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace); + can(OrgPermissionActions.Create, OrgPermissionSubjects.Project); // role permission can(OrgPermissionActions.Read, OrgPermissionSubjects.Role); can(OrgPermissionActions.Create, OrgPermissionSubjects.Role); @@ -413,6 +420,7 @@ const buildMemberPermission = () => { const { can, rules } = new AbilityBuilder>(createMongoAbility); can(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace); + can(OrgPermissionActions.Create, OrgPermissionSubjects.Project); can(OrgPermissionActions.Read, OrgPermissionSubjects.Member); can(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups); can(OrgPermissionActions.Read, OrgPermissionSubjects.Role); diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts index 557e71e6c..eefe6b63a 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts @@ -431,7 +431,7 @@ export const secretRotationQueueFactory = ({ numberOfSecrets: numberOfSecretsRotated, environment: secretRotation.environment.slug, secretPath: secretRotation.secretPath, - workspaceId: secretRotation.projectId + projectId: secretRotation.projectId } }); diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 97aa17874..9a6a71251 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -711,13 +711,13 @@ export const PROJECTS = { template: "The name of the project template, if specified, to apply to this project." }, DELETE: { - workspaceId: "The ID of the project to delete." + projectId: "The ID of the project to delete." }, GET: { - workspaceId: "The ID of the project." + projectId: "The ID of the project." }, UPDATE: { - workspaceId: "The ID of the project to update.", + projectId: "The ID of the project to update.", name: "The new name of the project.", projectDescription: "An optional description label for the project.", autoCapitalization: "Disable or enable auto-capitalization for the project.", @@ -729,10 +729,10 @@ export const PROJECTS = { secretDetectionIgnoreValues: "The list of secret values to ignore for secret detection." }, GET_KEY: { - workspaceId: "The ID of the project to get the key from." + projectId: "The ID of the project to get the key from." }, GET_SNAPSHOTS: { - workspaceId: "The ID of the project to get snapshots from.", + projectId: "The ID of the project to get snapshots from.", environment: "The environment to get snapshots from.", path: "The secret path to get snapshots from.", offset: "The offset to start from. If you enter 10, it will start from the 10th snapshot.", @@ -759,10 +759,10 @@ export const PROJECTS = { projectId: "The ID of the project to list groups for." }, LIST_INTEGRATION: { - workspaceId: "The ID of the project to list integrations for." + projectId: "The ID of the project to list integrations for." }, LIST_INTEGRATION_AUTHORIZATION: { - workspaceId: "The ID of the project to list integration auths for." + projectId: "The ID of the project to list integration auths for." }, LIST_SSH_CAS: { projectId: "The ID of the project to list SSH CAs for." @@ -815,15 +815,15 @@ export const PROJECT_USERS = { usernames: "A list of usernames to remove from the project." }, GET_USER_MEMBERSHIPS: { - workspaceId: "The ID of the project to get memberships from." + projectId: "The ID of the project to get memberships from." }, GET_USER_MEMBERSHIP: { - workspaceId: "The ID of the project to get memberships from.", + projectId: "The ID of the project to get memberships from.", membershipId: "The ID of the user's project membership.", username: "The username to get project membership of. Email is the default username." }, UPDATE_USER_MEMBERSHIP: { - workspaceId: "The ID of the project to update the membership for.", + projectId: "The ID of the project to update the membership for.", membershipId: "The ID of the membership to update.", roles: "A list of roles to update the membership to." } @@ -877,31 +877,31 @@ export const PROJECT_IDENTITIES = { export const ENVIRONMENTS = { CREATE: { - workspaceId: "The ID of the project to create the environment in.", + projectId: "The ID of the project to create the environment in.", name: "The name of the environment to create.", slug: "The slug of the environment to create.", position: "The position of the environment. The lowest number will be displayed as the first environment." }, UPDATE: { - workspaceId: "The ID of the project to update the environment in.", + projectId: "The ID of the project to update the environment in.", id: "The ID of the environment to update.", name: "The new name of the environment.", slug: "The new slug of the environment.", position: "The new position of the environment. The lowest number will be displayed as the first environment." }, DELETE: { - workspaceId: "The ID of the project to delete the environment from.", + projectId: "The ID of the project to delete the environment from.", id: "The ID of the environment to delete." }, GET: { - workspaceId: "The ID of the project the environment belongs to.", + projectId: "The ID of the project the environment belongs to.", id: "The ID of the environment to fetch." } } as const; export const FOLDERS = { LIST: { - workspaceId: "The ID of the project to list folders from.", + projectId: "The ID of the project to list folders from.", environment: "The slug of the environment to list folders from.", path: "The path to list folders from.", directory: "The directory to list folders from. (Deprecated in favor of path)", @@ -913,7 +913,7 @@ export const FOLDERS = { folderId: "The ID of the folder to get details." }, CREATE: { - workspaceId: "The ID of the project to create the folder in.", + projectId: "The ID of the project to create the folder in.", environment: "The slug of the environment to create the folder in.", name: "The name of the folder to create.", path: "The path of the folder to create.", @@ -927,12 +927,12 @@ export const FOLDERS = { path: "The path of the folder to update.", directory: "The new directory of the folder to update. (Deprecated in favor of path)", projectSlug: "The slug of the project where the folder is located.", - workspaceId: "The ID of the project where the folder is located.", + projectId: "The ID of the project where the folder is located.", description: "An optional description label for the folder." }, DELETE: { folderIdOrName: "The ID or name of the folder to delete.", - workspaceId: "The ID of the project to delete the folder from.", + projectId: "The ID of the project to delete the folder from.", environment: "The slug of the environment where the folder is located.", directory: "The directory of the folder to delete. (Deprecated in favor of path)", path: "The path of the folder to delete." @@ -964,7 +964,7 @@ export const RAW_SECRETS = { expand: "Whether or not to expand secret references.", recursive: "Whether or not to fetch all secrets from the specified base path, and all of its subdirectories. Note, the max depth is 20 deep.", - workspaceId: "The ID of the project to list secrets from.", + projectId: "The ID of the project to list secrets from.", workspaceSlug: "The slug of the project to list secrets from. This parameter is only applicable by machine identities.", environment: "The slug of the environment to list secrets from.", @@ -984,7 +984,7 @@ export const RAW_SECRETS = { secretValue: "The value of the secret to create.", skipMultilineEncoding: "Skip multiline encoding for the secret value.", type: "The type of the secret to create.", - workspaceId: "The ID of the project to create the secret in.", + projectId: "The ID of the project to create the secret in.", tagIds: "The ID of the tags to be attached to the created secret.", secretReminderRepeatDays: "Interval for secret rotation notifications, measured in days.", secretReminderNote: "Note to be attached in notification email." @@ -992,7 +992,7 @@ export const RAW_SECRETS = { GET: { expand: "Whether or not to expand secret references.", secretName: "The name of the secret to get.", - workspaceId: "The ID of the project to get the secret from.", + projectId: "The ID of the project to get the secret from.", workspaceSlug: "The slug of the project to get the secret from.", environment: "The slug of the environment to get the secret from.", secretPath: "The path of the secret to get.", @@ -1011,7 +1011,7 @@ export const RAW_SECRETS = { skipMultilineEncoding: "Skip multiline encoding for the secret value.", type: "The type of the secret to update.", projectSlug: "The slug of the project to update the secret in.", - workspaceId: "The ID of the project to update the secret in.", + projectId: "The ID of the project to update the secret in.", tagIds: "The ID of the tags to be attached to the updated secret.", secretReminderRepeatDays: "Interval for secret rotation notifications, measured in days.", secretReminderNote: "Note to be attached in notification email.", @@ -1025,11 +1025,11 @@ export const RAW_SECRETS = { secretPath: "The path of the secret.", type: "The type of the secret to delete.", projectSlug: "The slug of the project to delete the secret in.", - workspaceId: "The ID of the project where the secret is located." + projectId: "The ID of the project where the secret is located." }, GET_REFERENCE_TREE: { secretName: "The name of the secret to get the reference tree for.", - workspaceId: "The ID of the project where the secret is located.", + projectId: "The ID of the project where the secret is located.", environment: "The slug of the environment where the the secret is located.", secretPath: "The folder path where the secret is located." }, @@ -1043,7 +1043,7 @@ export const RAW_SECRETS = { export const SECRET_IMPORTS = { LIST: { - workspaceId: "The ID of the project to list secret imports from.", + projectId: "The ID of the project to list secret imports from.", environment: "The slug of the environment to list secret imports from.", path: "The path to list secret imports from." }, @@ -1053,7 +1053,7 @@ export const SECRET_IMPORTS = { CREATE: { environment: "The slug of the environment to import into.", path: "The path to import into.", - workspaceId: "The ID of the project you are working in.", + projectId: "The ID of the project you are working in.", isReplication: "When true, secrets from the source will be automatically sent to the destination. If approval policies exist at the destination, the secrets will be sent as approval requests instead of being applied immediately.", import: { @@ -1070,10 +1070,10 @@ export const SECRET_IMPORTS = { position: "The new position of the secret import. The lowest number will be displayed as the first import." }, path: "The path of the secret import to update.", - workspaceId: "The ID of the project where the secret import is located." + projectId: "The ID of the project where the secret import is located." }, DELETE: { - workspaceId: "The ID of the project to delete the secret import from.", + projectId: "The ID of the project to delete the secret import from.", secretImportId: "The ID of the secret import to delete.", environment: "The slug of the environment where the secret import is located.", path: "The path of the secret import to delete." diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 1df89cd19..b9dc65676 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -328,6 +328,7 @@ import { registerV1Routes } from "./v1"; import { initializeOauthConfigSync } from "./v1/sso-router"; import { registerV2Routes } from "./v2"; import { registerV3Routes } from "./v3"; +import { registerV4Routes } from "./v4"; const histogram = monitorEventLoopDelay({ resolution: 20 }); histogram.enable(); @@ -2295,6 +2296,7 @@ export const registerRoutes = async ( { prefix: "/api/v2" } ); await server.register(registerV3Routes, { prefix: "/api/v3" }); + await server.register(registerV4Routes, { prefix: "/api/v4" }); server.addHook("onClose", async () => { cronJobs.forEach((job) => job.stop()); diff --git a/backend/src/server/routes/v1/dashboard-router.ts b/backend/src/server/routes/v1/dashboard-router.ts index a54bd5ccf..c394ee8e9 100644 --- a/backend/src/server/routes/v1/dashboard-router.ts +++ b/backend/src/server/routes/v1/dashboard-router.ts @@ -207,7 +207,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { const environments = req.query.environments.split(","); if (!projectId || environments.length === 0) - throw new BadRequestError({ message: "Missing workspace id or environment(s)" }); + throw new BadRequestError({ message: "Missing project id or environment(s)" }); const { shouldUseSecretV2Bridge } = await server.services.projectBot.getBotKey(projectId); @@ -474,7 +474,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secretCountFromEnv, - workspaceId: projectId, + projectId, environment, secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -696,7 +696,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { includeSecretRotations } = req.query; - if (!projectId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" }); + if (!projectId || !environment) throw new BadRequestError({ message: "Missing project id or environment" }); const { shouldUseSecretV2Bridge } = await server.services.projectBot.getBotKey(projectId); @@ -1001,7 +1001,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secretCount, - workspaceId: projectId, + projectId, environment, secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1168,7 +1168,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secretCountForEnv, - workspaceId: projectId, + projectId, environment, secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1361,7 +1361,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: projectId, + projectId, environment, secretPath, channel: getUserAgentType(req.headers["user-agent"]), diff --git a/backend/src/server/routes/v1/deprecated-project-env-router.ts b/backend/src/server/routes/v1/deprecated-project-env-router.ts new file mode 100644 index 000000000..1a187e2b1 --- /dev/null +++ b/backend/src/server/routes/v1/deprecated-project-env-router.ts @@ -0,0 +1,298 @@ +import { z } from "zod"; + +import { ProjectEnvironmentsSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, ENVIRONMENTS } from "@app/lib/api-docs"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { slugSchema } from "@app/server/lib/schemas"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; + +export const registerDeprecatedProjectEnvRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "GET", + url: "/:workspaceId/environments/:envId", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Environments], + description: "Get Environment", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + // NOTE(daniel): workspaceId isn't used, but we need to keep it for backwards compatibility. The endpoint defined below, uses no project ID, and is takes a pure environment ID. + workspaceId: z.string().trim().describe(ENVIRONMENTS.GET.projectId), + envId: z.string().trim().describe(ENVIRONMENTS.GET.id) + }), + response: { + 200: z.object({ + environment: ProjectEnvironmentsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const environment = await server.services.projectEnv.getEnvironmentById({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + id: req.params.envId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: environment.projectId, + event: { + type: EventType.GET_ENVIRONMENT, + metadata: { + id: environment.id + } + } + }); + + return { environment }; + } + }); + + server.route({ + method: "GET", + url: "/environments/:envId", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Environments], + description: "Get Environment by ID", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + envId: z.string().trim().describe(ENVIRONMENTS.GET.id) + }), + response: { + 200: z.object({ + environment: ProjectEnvironmentsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const environment = await server.services.projectEnv.getEnvironmentById({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + id: req.params.envId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: environment.projectId, + event: { + type: EventType.GET_ENVIRONMENT, + metadata: { + id: environment.id + } + } + }); + + return { environment }; + } + }); + + server.route({ + method: "POST", + url: "/:workspaceId/environments", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Environments], + description: "Create environment", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(ENVIRONMENTS.CREATE.projectId) + }), + body: z.object({ + name: z.string().trim().describe(ENVIRONMENTS.CREATE.name), + position: z.number().min(1).optional().describe(ENVIRONMENTS.CREATE.position), + slug: slugSchema({ max: 64 }).describe(ENVIRONMENTS.CREATE.slug) + }), + response: { + 200: z.object({ + message: z.string(), + workspace: z.string(), + environment: ProjectEnvironmentsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const environment = await server.services.projectEnv.createEnvironment({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + projectId: req.params.workspaceId, + ...req.body + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: environment.projectId, + event: { + type: EventType.CREATE_ENVIRONMENT, + metadata: { + name: environment.name, + slug: environment.slug + } + } + }); + return { + message: "Successfully created new environment", + workspace: req.params.workspaceId, + environment + }; + } + }); + + server.route({ + method: "PATCH", + url: "/:workspaceId/environments/:id", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Environments], + description: "Update environment", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(ENVIRONMENTS.UPDATE.projectId), + id: z.string().trim().describe(ENVIRONMENTS.UPDATE.id) + }), + body: z.object({ + slug: slugSchema({ max: 64 }).optional().describe(ENVIRONMENTS.UPDATE.slug), + name: z.string().trim().optional().describe(ENVIRONMENTS.UPDATE.name), + position: z.number().optional().describe(ENVIRONMENTS.UPDATE.position) + }), + response: { + 200: z.object({ + message: z.string(), + workspace: z.string(), + environment: ProjectEnvironmentsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { environment, old } = await server.services.projectEnv.updateEnvironment({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + id: req.params.id, + ...req.body + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: environment.projectId, + event: { + type: EventType.UPDATE_ENVIRONMENT, + metadata: { + oldName: old.name, + oldSlug: old.slug, + oldPos: old.position, + newName: environment.name, + newSlug: environment.slug, + newPos: environment.position + } + } + }); + + return { + message: "Successfully updated environment", + workspace: req.params.workspaceId, + environment + }; + } + }); + + server.route({ + method: "DELETE", + url: "/:workspaceId/environments/:id", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Environments], + description: "Delete environment", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(ENVIRONMENTS.DELETE.projectId), + id: z.string().trim().describe(ENVIRONMENTS.DELETE.id) + }), + response: { + 200: z.object({ + message: z.string(), + workspace: z.string(), + environment: ProjectEnvironmentsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const environment = await server.services.projectEnv.deleteEnvironment({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + id: req.params.id + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: environment.projectId, + event: { + type: EventType.DELETE_ENVIRONMENT, + metadata: { + slug: environment.slug, + name: environment.name + } + } + }); + + return { + message: "Successfully deleted environment", + workspace: req.params.workspaceId, + environment + }; + } + }); +}; diff --git a/backend/src/server/routes/v1/deprecated-project-membership-router.ts b/backend/src/server/routes/v1/deprecated-project-membership-router.ts new file mode 100644 index 000000000..ab225929f --- /dev/null +++ b/backend/src/server/routes/v1/deprecated-project-membership-router.ts @@ -0,0 +1,378 @@ +import { z } from "zod"; + +import { + OrgMembershipsSchema, + ProjectMembershipsSchema, + ProjectUserMembershipRolesSchema, + UserEncryptionKeysSchema, + UsersSchema +} from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, PROJECT_USERS } from "@app/lib/api-docs"; +import { ms } from "@app/lib/ms"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; +import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types"; + +export const registerDeprecatedProjectMembershipRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "GET", + url: "/:workspaceId/memberships", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], + description: "Return project user memberships", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIPS.projectId) + }), + response: { + 200: z.object({ + memberships: ProjectMembershipsSchema.extend({ + user: UsersSchema.pick({ + email: true, + firstName: true, + lastName: true, + id: true, + username: true + }).merge(UserEncryptionKeysSchema.pick({ publicKey: true })), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ) + }) + .omit({ updatedAt: true }) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const memberships = await server.services.projectMembership.getProjectMemberships({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId + }); + return { memberships }; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId/memberships/:membershipId", + config: { + rateLimit: readLimit + }, + schema: { + description: "Return project user membership", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.projectId), + membershipId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.membershipId) + }), + response: { + 200: z.object({ + membership: ProjectMembershipsSchema.extend({ + user: UsersSchema.pick({ + email: true, + firstName: true, + lastName: true, + id: true, + username: true + }).merge(UserEncryptionKeysSchema.pick({ publicKey: true })), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ) + }).omit({ updatedAt: true }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const membership = await server.services.projectMembership.getProjectMembershipById({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + id: req.params.membershipId + }); + return { membership }; + } + }); + + server.route({ + method: "POST", + url: "/:workspaceId/memberships/details", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], + description: "Return project user memberships", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.projectId) + }), + body: z.object({ + username: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.username) + }), + response: { + 200: z.object({ + membership: ProjectMembershipsSchema.extend({ + user: UsersSchema.pick({ + email: true, + firstName: true, + lastName: true, + id: true + }).merge(UserEncryptionKeysSchema.pick({ publicKey: true })), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ) + }).omit({ createdAt: true, updatedAt: true }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const membership = await server.services.projectMembership.getProjectMembershipByUsername({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + username: req.body.username + }); + return { membership }; + } + }); + + server.route({ + method: "POST", + url: "/:workspaceId/memberships", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + workspaceId: z.string().trim() + }), + body: z.object({ + members: z + .object({ + orgMembershipId: z.string().trim(), + workspaceEncryptedKey: z.string().trim(), + workspaceEncryptedNonce: z.string().trim() + }) + .array() + .min(1) + }), + response: { + 200: z.object({ + success: z.boolean(), + data: OrgMembershipsSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const data = await server.services.projectMembership.addUsersToProject({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + members: req.body.members + }); + + await server.services.auditLog.createAuditLog({ + projectId: req.params.workspaceId, + ...req.auditLogInfo, + event: { + type: EventType.ADD_BATCH_PROJECT_MEMBER, + metadata: data.map(({ userId }) => ({ + userId: userId || "", + email: "" + })) + } + }); + + return { data, success: true }; + } + }); + + server.route({ + method: "PATCH", + url: "/:workspaceId/memberships/:membershipId", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], + description: "Update project user membership", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECT_USERS.UPDATE_USER_MEMBERSHIP.projectId), + membershipId: z.string().trim().describe(PROJECT_USERS.UPDATE_USER_MEMBERSHIP.membershipId) + }), + body: z.object({ + roles: z + .array( + z.union([ + z.object({ + role: z.string(), + isTemporary: z.literal(false).default(false) + }), + z.object({ + role: z.string(), + isTemporary: z.literal(true), + temporaryMode: z.nativeEnum(ProjectUserMembershipTemporaryMode), + temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"), + temporaryAccessStartTime: z.string().datetime() + }) + ]) + ) + .min(1) + .refine((data) => data.some(({ isTemporary }) => !isTemporary), "At least one long lived role is required") + .describe(PROJECT_USERS.UPDATE_USER_MEMBERSHIP.roles) + }), + response: { + 200: z.object({ + roles: ProjectUserMembershipRolesSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const roles = await server.services.projectMembership.updateProjectMembership({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + membershipId: req.params.membershipId, + roles: req.body.roles + }); + + // await server.services.auditLog.createAuditLog({ + // ...req.auditLogInfo, + // projectId: req.params.workspaceId, + // event: { + // type: EventType.UPDATE_USER_WORKSPACE_ROLE, + // metadata: { + // userId: membership.userId, + // newRole: req.body.role, + // oldRole: membership.role, + // email: "" + // } + // } + // }); + return { roles }; + } + }); + + server.route({ + method: "DELETE", + url: "/:workspaceId/memberships/:membershipId", + config: { + rateLimit: writeLimit + }, + schema: { + description: "Delete project user membership", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim(), + membershipId: z.string().trim() + }), + response: { + 200: z.object({ + membership: ProjectMembershipsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const membership = await server.services.projectMembership.deleteProjectMembership({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + membershipId: req.params.membershipId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.params.workspaceId, + event: { + type: EventType.REMOVE_PROJECT_MEMBER, + metadata: { + userId: membership.userId, + email: "" + } + } + }); + return { membership }; + } + }); +}; diff --git a/backend/src/server/routes/v1/deprecated-project-router.ts b/backend/src/server/routes/v1/deprecated-project-router.ts new file mode 100644 index 000000000..687d95b9b --- /dev/null +++ b/backend/src/server/routes/v1/deprecated-project-router.ts @@ -0,0 +1,728 @@ +import { z } from "zod"; + +import { + IntegrationsSchema, + ProjectRolesSchema, + ProjectSlackConfigsSchema, + ProjectSshConfigsSchema, + ProjectType, + SortDirection +} from "@app/db/schemas"; +import { ProjectMicrosoftTeamsConfigsSchema } from "@app/db/schemas/project-microsoft-teams-configs"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; +import { CharacterType, characterValidator } from "@app/lib/validator/validate-string"; +import { re2Validator } from "@app/lib/zod"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; +import { validateMicrosoftTeamsChannelsSchema } from "@app/services/microsoft-teams/microsoft-teams-fns"; +import { ProjectFilterType, SearchProjectSortBy } from "@app/services/project/project-types"; +import { validateSlackChannelsField } from "@app/services/slack/slack-auth-validators"; +import { WorkflowIntegration } from "@app/services/workflow-integration/workflow-integration-types"; + +import { integrationAuthPubSchema, SanitizedProjectSchema } from "../sanitizedSchemas"; + +const projectWithEnv = SanitizedProjectSchema.merge( + z.object({ + _id: z.string(), + environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array() + }) +); + +export const registerDeprecatedProjectRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "GET", + url: "/", + config: { + rateLimit: readLimit + }, + schema: { + querystring: z.object({ + includeRoles: z + .enum(["true", "false"]) + .default("false") + .transform((value) => value === "true"), + type: z.nativeEnum(ProjectType).optional() + }), + response: { + 200: z.object({ + workspaces: projectWithEnv + .extend({ + roles: ProjectRolesSchema.array().optional() + }) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaces = await server.services.project.getProjects({ + includeRoles: req.query.includeRoles, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + type: req.query.type + }); + return { workspaces }; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "Get project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECTS.GET.projectId) + }), + response: { + 200: z.object({ + workspace: projectWithEnv.optional() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspace = await server.services.project.getAProject({ + filter: { + type: ProjectFilterType.ID, + projectId: req.params.workspaceId + }, + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId + }); + return { workspace }; + } + }); + + server.route({ + method: "DELETE", + url: "/:workspaceId", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "Delete project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECTS.DELETE.projectId) + }), + response: { + 200: z.object({ + workspace: SanitizedProjectSchema.optional() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspace = await server.services.project.deleteProject({ + filter: { + type: ProjectFilterType.ID, + projectId: req.params.workspaceId + }, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: req.params.workspaceId, + event: { + type: EventType.DELETE_PROJECT, + metadata: workspace + } + }); + + return { workspace }; + } + }); + + server.route({ + method: "PATCH", + url: "/:workspaceId", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "Update project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECTS.UPDATE.projectId) + }), + body: z.object({ + name: z + .string() + .trim() + .max(64, { message: "Name must be 64 or fewer characters" }) + .optional() + .describe(PROJECTS.UPDATE.name), + description: z + .string() + .trim() + .max(256, { message: "Description must be 256 or fewer characters" }) + .optional() + .describe(PROJECTS.UPDATE.projectDescription), + autoCapitalization: z.boolean().optional().describe(PROJECTS.UPDATE.autoCapitalization), + hasDeleteProtection: z.boolean().optional().describe(PROJECTS.UPDATE.hasDeleteProtection), + slug: z + .string() + .trim() + .max(64, { message: "Slug must be 64 characters or fewer" }) + .refine(re2Validator(/^[a-z0-9]+(?:[_-][a-z0-9]+)*$/), { + message: + "Project slug can only contain lowercase letters and numbers, with optional single hyphens (-) or underscores (_) between words. Cannot start or end with a hyphen or underscore." + }) + .optional() + .describe(PROJECTS.UPDATE.slug), + secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing), + showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy), + defaultProduct: z.nativeEnum(ProjectType).optional().describe(PROJECTS.UPDATE.defaultProduct), + secretDetectionIgnoreValues: z + .array(z.string()) + .optional() + .describe(PROJECTS.UPDATE.secretDetectionIgnoreValues) + }), + response: { + 200: z.object({ + workspace: SanitizedProjectSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspace = await server.services.project.updateProject({ + filter: { + type: ProjectFilterType.ID, + projectId: req.params.workspaceId + }, + update: { + name: req.body.name, + description: req.body.description, + autoCapitalization: req.body.autoCapitalization, + defaultProduct: req.body.defaultProduct, + hasDeleteProtection: req.body.hasDeleteProtection, + slug: req.body.slug, + secretSharing: req.body.secretSharing, + showSnapshotsLegacy: req.body.showSnapshotsLegacy, + secretDetectionIgnoreValues: req.body.secretDetectionIgnoreValues + }, + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: req.params.workspaceId, + event: { + type: EventType.UPDATE_PROJECT, + metadata: req.body + } + }); + + return { + workspace + }; + } + }); + + server.route({ + method: "PUT", + url: "/:workspaceSlug/audit-logs-retention", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + workspaceSlug: z.string().trim() + }), + body: z.object({ + auditLogsRetentionDays: z.number().min(0) + }), + response: { + 200: z.object({ + message: z.string(), + workspace: SanitizedProjectSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspace = await server.services.project.updateAuditLogsRetention({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + filter: { + type: ProjectFilterType.SLUG, + slug: req.params.workspaceSlug, + orgId: req.permission.orgId + }, + auditLogsRetentionDays: req.body.auditLogsRetentionDays + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: workspace.id, + event: { + type: EventType.UPDATE_PROJECT, + metadata: req.body + } + }); + + return { + message: "Successfully updated project's audit logs retention period", + workspace + }; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId/integrations", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Integrations], + description: "List integrations for a project.", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION.projectId) + }), + response: { + 200: z.object({ + integrations: IntegrationsSchema.merge( + z.object({ + environment: z.object({ + id: z.string(), + name: z.string(), + slug: z.string() + }) + }) + ).array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const integrations = await server.services.integration.listIntegrationByProject({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId + }); + return { integrations }; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId/authorizations", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Integrations], + description: "List integration auth objects for a workspace.", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + workspaceId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION_AUTHORIZATION.projectId) + }), + response: { + 200: z.object({ + authorizations: integrationAuthPubSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const authorizations = await server.services.integrationAuth.listIntegrationAuthByProjectId({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId + }); + return { authorizations }; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId/ssh-config", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + workspaceId: z.string().trim() + }), + response: { + 200: ProjectSshConfigsSchema.pick({ + id: true, + createdAt: true, + updatedAt: true, + projectId: true, + defaultUserSshCaId: true, + defaultHostSshCaId: true + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const sshConfig = await server.services.project.getProjectSshConfig({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: sshConfig.projectId, + event: { + type: EventType.GET_PROJECT_SSH_CONFIG, + metadata: { + id: sshConfig.id, + projectId: sshConfig.projectId + } + } + }); + + return sshConfig; + } + }); + + server.route({ + method: "PATCH", + url: "/:workspaceId/ssh-config", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + workspaceId: z.string().trim() + }), + body: z.object({ + defaultUserSshCaId: z.string().optional(), + defaultHostSshCaId: z.string().optional() + }), + response: { + 200: ProjectSshConfigsSchema.pick({ + id: true, + createdAt: true, + updatedAt: true, + projectId: true, + defaultUserSshCaId: true, + defaultHostSshCaId: true + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const sshConfig = await server.services.project.updateProjectSshConfig({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + ...req.body + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: sshConfig.projectId, + event: { + type: EventType.UPDATE_PROJECT_SSH_CONFIG, + metadata: { + id: sshConfig.id, + projectId: sshConfig.projectId, + defaultUserSshCaId: sshConfig.defaultUserSshCaId, + defaultHostSshCaId: sshConfig.defaultHostSshCaId + } + } + }); + + return sshConfig; + } + }); + + server.route({ + method: "GET", + url: "/:workspaceId/workflow-integration-config/:integration", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + workspaceId: z.string().trim(), + integration: z.nativeEnum(WorkflowIntegration) + }), + response: { + 200: z.discriminatedUnion("integration", [ + ProjectSlackConfigsSchema.pick({ + id: true, + isAccessRequestNotificationEnabled: true, + accessRequestChannels: true, + isSecretRequestNotificationEnabled: true, + secretRequestChannels: true + }).merge( + z.object({ + integration: z.literal(WorkflowIntegration.SLACK), + integrationId: z.string() + }) + ), + ProjectMicrosoftTeamsConfigsSchema.pick({ + id: true, + isAccessRequestNotificationEnabled: true, + accessRequestChannels: true, + isSecretRequestNotificationEnabled: true, + secretRequestChannels: true + }).merge( + z.object({ + integration: z.literal(WorkflowIntegration.MICROSOFT_TEAMS), + integrationId: z.string() + }) + ) + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const config = await server.services.project.getProjectWorkflowIntegrationConfig({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + integration: req.params.integration + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.params.workspaceId, + event: { + type: EventType.GET_PROJECT_WORKFLOW_INTEGRATION_CONFIG, + metadata: { + id: config.id, + integration: config.integration + } + } + }); + + return config; + } + }); + + server.route({ + method: "DELETE", + url: "/:projectId/workflow-integration/:integration/:integrationId", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + projectId: z.string().trim(), + integration: z.nativeEnum(WorkflowIntegration), + integrationId: z.string() + }), + response: { + 200: z.object({ + integrationConfig: z.object({ + id: z.string() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const deletedIntegration = await server.services.project.deleteProjectWorkflowIntegration({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + integration: req.params.integration, + integrationId: req.params.integrationId + }); + + return { + integrationConfig: deletedIntegration + }; + } + }); + + server.route({ + method: "PUT", + url: "/:workspaceId/workflow-integration", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + workspaceId: z.string().trim() + }), + + body: z.discriminatedUnion("integration", [ + z.object({ + integration: z.literal(WorkflowIntegration.SLACK), + integrationId: z.string(), + accessRequestChannels: validateSlackChannelsField, + secretRequestChannels: validateSlackChannelsField, + isAccessRequestNotificationEnabled: z.boolean(), + isSecretRequestNotificationEnabled: z.boolean() + }), + z.object({ + integration: z.literal(WorkflowIntegration.MICROSOFT_TEAMS), + integrationId: z.string(), + accessRequestChannels: validateMicrosoftTeamsChannelsSchema, + secretRequestChannels: validateMicrosoftTeamsChannelsSchema, + isAccessRequestNotificationEnabled: z.boolean(), + isSecretRequestNotificationEnabled: z.boolean() + }) + ]), + response: { + 200: z.discriminatedUnion("integration", [ + ProjectSlackConfigsSchema.pick({ + id: true, + isAccessRequestNotificationEnabled: true, + accessRequestChannels: true, + isSecretRequestNotificationEnabled: true, + secretRequestChannels: true + }).merge( + z.object({ + integration: z.literal(WorkflowIntegration.SLACK), + integrationId: z.string() + }) + ), + ProjectMicrosoftTeamsConfigsSchema.pick({ + id: true, + isAccessRequestNotificationEnabled: true, + isSecretRequestNotificationEnabled: true + }).merge( + z.object({ + integration: z.literal(WorkflowIntegration.MICROSOFT_TEAMS), + integrationId: z.string(), + accessRequestChannels: validateMicrosoftTeamsChannelsSchema, + secretRequestChannels: validateMicrosoftTeamsChannelsSchema + }) + ) + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workflowIntegrationConfig = await server.services.project.updateProjectWorkflowIntegration({ + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + projectId: req.params.workspaceId, + ...req.body + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.params.workspaceId, + event: { + type: EventType.UPDATE_PROJECT_WORKFLOW_INTEGRATION_CONFIG, + metadata: { + id: workflowIntegrationConfig.id, + integrationId: workflowIntegrationConfig.integrationId, + integration: workflowIntegrationConfig.integration, + isAccessRequestNotificationEnabled: workflowIntegrationConfig.isAccessRequestNotificationEnabled, + accessRequestChannels: workflowIntegrationConfig.accessRequestChannels, + isSecretRequestNotificationEnabled: workflowIntegrationConfig.isSecretRequestNotificationEnabled, + secretRequestChannels: workflowIntegrationConfig.secretRequestChannels + } + } + }); + + return workflowIntegrationConfig; + } + }); + + server.route({ + method: "POST", + url: "/search", + config: { + rateLimit: readLimit + }, + schema: { + body: z.object({ + limit: z.number().default(100), + offset: z.number().default(0), + type: z.nativeEnum(ProjectType).optional(), + orderBy: z.nativeEnum(SearchProjectSortBy).optional().default(SearchProjectSortBy.NAME), + orderDirection: z.nativeEnum(SortDirection).optional().default(SortDirection.ASC), + name: z + .string() + .trim() + .refine((val) => characterValidator([CharacterType.AlphaNumeric, CharacterType.Hyphen])(val), { + message: "Invalid pattern: only alphanumeric characters, - are allowed." + }) + .optional() + }), + response: { + 200: z.object({ + projects: SanitizedProjectSchema.extend({ isMember: z.boolean() }).array(), + totalCount: z.number() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { docs: projects, totalCount } = await server.services.project.searchProjects({ + permission: req.permission, + ...req.body + }); + + return { projects, totalCount }; + } + }); +}; diff --git a/backend/src/server/routes/v1/deprecated-secret-folder-router.ts b/backend/src/server/routes/v1/deprecated-secret-folder-router.ts new file mode 100644 index 000000000..ecb955025 --- /dev/null +++ b/backend/src/server/routes/v1/deprecated-secret-folder-router.ts @@ -0,0 +1,444 @@ +import { z } from "zod"; + +import { SecretFoldersSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, FOLDERS } from "@app/lib/api-docs"; +import { prefixWithSlash, removeTrailingSlash } from "@app/lib/fn"; +import { isValidFolderName } from "@app/lib/validator"; +import { readLimit, secretsLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; + +import { booleanSchema } from "../sanitizedSchemas"; + +export const registerDeprecatedSecretFolderRouter = async (server: FastifyZodProvider) => { + server.route({ + url: "/", + method: "POST", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + description: "Create folders", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + workspaceId: z.string().trim().describe(FOLDERS.CREATE.projectId), + environment: z.string().trim().describe(FOLDERS.CREATE.environment), + name: z + .string() + .trim() + .describe(FOLDERS.CREATE.name) + .refine((name) => isValidFolderName(name), { + message: "Invalid folder name. Only alphanumeric characters, dashes, and underscores are allowed." + }), + path: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) // Transformations get skipped if path is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.CREATE.path) + .optional(), + // backward compatibility with cli + directory: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) // Transformations get skipped if directory is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.CREATE.directory) + .optional(), + description: z.string().optional().nullable().describe(FOLDERS.CREATE.description) + }), + response: { + 200: z.object({ + folder: SecretFoldersSchema.extend({ + path: z.string() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const path = req.body.path || req.body.directory || "/"; + const folder = await server.services.folder.createFolder({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body, + projectId: req.body.workspaceId, + path, + description: req.body.description + }); + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.body.workspaceId, + event: { + type: EventType.CREATE_FOLDER, + metadata: { + environment: req.body.environment, + folderId: folder.id, + folderName: folder.name, + folderPath: path, + ...(req.body.description ? { description: req.body.description } : {}) + } + } + }); + return { folder }; + } + }); + + server.route({ + url: "/:folderId", + method: "PATCH", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + description: "Update folder", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + // old way this was name + folderId: z.string().describe(FOLDERS.UPDATE.folderId) + }), + body: z.object({ + workspaceId: z.string().trim().describe(FOLDERS.UPDATE.projectId), + environment: z.string().trim().describe(FOLDERS.UPDATE.environment), + name: z + .string() + .trim() + .describe(FOLDERS.UPDATE.name) + .refine((name) => isValidFolderName(name), { + message: "Invalid folder name. Only alphanumeric characters, dashes, and underscores are allowed." + }), + path: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) // Transformations get skipped if path is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.UPDATE.path) + .optional(), + // backward compatibility with cli + directory: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) // Transformations get skipped if directory is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.UPDATE.directory) + .optional(), + description: z.string().optional().nullable().describe(FOLDERS.UPDATE.description) + }), + response: { + 200: z.object({ + folder: SecretFoldersSchema.extend({ + path: z.string() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const path = req.body.path || req.body.directory || "/"; + const { folder, old } = await server.services.folder.updateFolder({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body, + projectId: req.body.workspaceId, + id: req.params.folderId, + path + }); + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.body.workspaceId, + event: { + type: EventType.UPDATE_FOLDER, + metadata: { + environment: req.body.environment, + folderId: folder.id, + folderPath: path, + newFolderName: folder.name, + oldFolderName: old.name + } + } + }); + return { folder }; + } + }); + + server.route({ + url: "/batch", + method: "PATCH", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + description: "Update folders by batch", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + projectSlug: z.string().trim().describe(FOLDERS.UPDATE.projectSlug), + folders: z + .object({ + id: z.string().describe(FOLDERS.UPDATE.folderId), + environment: z.string().trim().describe(FOLDERS.UPDATE.environment), + name: z + .string() + .trim() + .describe(FOLDERS.UPDATE.name) + .refine((name) => isValidFolderName(name), { + message: "Invalid folder name. Only alphanumeric characters, dashes, and underscores are allowed." + }), + path: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) + .transform(removeTrailingSlash) + .describe(FOLDERS.UPDATE.path), + description: z.string().optional().nullable().describe(FOLDERS.UPDATE.description) + }) + .array() + .min(1) + }), + response: { + 200: z.object({ + folders: SecretFoldersSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { newFolders, oldFolders, projectId } = await server.services.folder.updateManyFolders({ + ...req.body, + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId + }); + + await Promise.all( + req.body.folders.map(async (folder, index) => { + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId, + event: { + type: EventType.UPDATE_FOLDER, + metadata: { + environment: oldFolders[index].envId, + folderId: oldFolders[index].id, + folderPath: folder.path, + newFolderName: newFolders[index].name, + oldFolderName: oldFolders[index].name + } + } + }); + }) + ); + + return { folders: newFolders }; + } + }); + + // TODO(daniel): Expose this route in api reference and write docs for it. + server.route({ + method: "DELETE", + url: "/:folderIdOrName", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + description: "Delete a folder", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + folderIdOrName: z.string().describe(FOLDERS.DELETE.folderIdOrName) + }), + body: z.object({ + workspaceId: z.string().trim().describe(FOLDERS.DELETE.projectId), + environment: z.string().trim().describe(FOLDERS.DELETE.environment), + path: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) // Transformations get skipped if path is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.DELETE.path) + .optional(), + // keep this here as cli need directory + directory: z + .string() + .trim() + .default("/") + .transform(prefixWithSlash) // Transformations get skipped if directory is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.DELETE.directory) + .optional() + }), + response: { + 200: z.object({ + folder: SecretFoldersSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const path = req.body.path || req.body.directory || "/"; + const folder = await server.services.folder.deleteFolder({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body, + projectId: req.body.workspaceId, + idOrName: req.params.folderIdOrName, + path + }); + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.body.workspaceId, + event: { + type: EventType.DELETE_FOLDER, + metadata: { + environment: req.body.environment, + folderId: folder.id, + folderPath: path, + folderName: folder.name + } + } + }); + return { folder }; + } + }); + + server.route({ + method: "GET", + url: "/", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + description: "Get folders", + security: [ + { + bearerAuth: [] + } + ], + querystring: z.object({ + workspaceId: z.string().trim().describe(FOLDERS.LIST.projectId), + environment: z.string().trim().describe(FOLDERS.LIST.environment), + lastSecretModified: z.string().datetime().trim().optional().describe(FOLDERS.LIST.lastSecretModified), + path: z + .string() + .trim() + .transform(prefixWithSlash) // Transformations get skipped if path is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.LIST.path) + .optional(), + // backward compatibility with cli + directory: z + .string() + .trim() + .transform(prefixWithSlash) // Transformations get skipped if directory is undefined + .transform(removeTrailingSlash) + .describe(FOLDERS.LIST.directory) + .optional(), + recursive: booleanSchema.default(false).describe(FOLDERS.LIST.recursive) + }), + response: { + 200: z.object({ + folders: SecretFoldersSchema.extend({ + relativePath: z.string().optional() + }).array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const path = req.query.path || req.query.directory || "/"; + const folders = await server.services.folder.getFolders({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.query, + projectId: req.query.workspaceId, + path + }); + return { folders }; + } + }); + + server.route({ + method: "GET", + url: "/:id", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + description: "Get folder by id", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + id: z.string().trim().describe(FOLDERS.GET_BY_ID.folderId) + }), + response: { + 200: z.object({ + folder: SecretFoldersSchema.extend({ + environment: z.object({ + envId: z.string(), + envName: z.string(), + envSlug: z.string() + }), + path: z.string(), + projectId: z.string() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const folder = await server.services.folder.getFolderById({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.id + }); + return { folder }; + } + }); +}; diff --git a/backend/src/server/routes/v1/deprecated-secret-import-router.ts b/backend/src/server/routes/v1/deprecated-secret-import-router.ts new file mode 100644 index 000000000..2fdbe4216 --- /dev/null +++ b/backend/src/server/routes/v1/deprecated-secret-import-router.ts @@ -0,0 +1,472 @@ +import { z } from "zod"; + +import { SecretImportsSchema, SecretsSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, SECRET_IMPORTS } from "@app/lib/api-docs"; +import { removeTrailingSlash } from "@app/lib/fn"; +import { readLimit, secretsLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; + +import { secretRawSchema } from "../sanitizedSchemas"; + +export const registerDeprecatedSecretImportRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "POST", + url: "/", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], + description: "Create secret imports", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + workspaceId: z.string().trim().describe(SECRET_IMPORTS.CREATE.projectId), + environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.path), + import: z.object({ + environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.import.environment), + path: z.string().trim().transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.import.path) + }), + isReplication: z.boolean().default(false).describe(SECRET_IMPORTS.CREATE.isReplication) + }), + response: { + 200: z.object({ + message: z.string(), + secretImport: SecretImportsSchema.omit({ importEnv: true }).merge( + z.object({ + importEnv: z.object({ name: z.string(), slug: z.string(), id: z.string() }) + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretImport = await server.services.secretImport.createImport({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body, + projectId: req.body.workspaceId, + data: req.body.import + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.body.workspaceId, + event: { + type: EventType.CREATE_SECRET_IMPORT, + metadata: { + secretImportId: secretImport.id, + folderId: secretImport.folderId, + importFromSecretPath: secretImport.importPath, + importFromEnvironment: secretImport.importEnv.slug, + importToEnvironment: req.body.environment, + importToSecretPath: req.body.path + } + } + }); + return { message: "Successfully created secret import", secretImport }; + } + }); + + server.route({ + method: "PATCH", + url: "/:secretImportId", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], + description: "Update secret imports", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretImportId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.secretImportId) + }), + body: z.object({ + workspaceId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.projectId), + environment: z.string().trim().describe(SECRET_IMPORTS.UPDATE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.UPDATE.path), + import: z.object({ + environment: z.string().trim().optional().describe(SECRET_IMPORTS.UPDATE.import.environment), + path: z + .string() + .trim() + .optional() + .transform((val) => (val ? removeTrailingSlash(val) : val)) + .describe(SECRET_IMPORTS.UPDATE.import.path), + position: z.number().optional().describe(SECRET_IMPORTS.UPDATE.import.position) + }) + }), + response: { + 200: z.object({ + message: z.string(), + secretImport: SecretImportsSchema.omit({ importEnv: true }).merge( + z.object({ + importEnv: z.object({ name: z.string(), slug: z.string(), id: z.string() }) + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretImport = await server.services.secretImport.updateImport({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.secretImportId, + ...req.body, + projectId: req.body.workspaceId, + data: req.body.import + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.body.workspaceId, + event: { + type: EventType.UPDATE_SECRET_IMPORT, + metadata: { + secretImportId: secretImport.id, + folderId: secretImport.folderId, + position: secretImport.position, + importToEnvironment: req.body.environment, + importToSecretPath: req.body.path + } + } + }); + + return { message: "Successfully updated secret import", secretImport }; + } + }); + + server.route({ + method: "DELETE", + url: "/:secretImportId", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], + description: "Delete secret imports", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretImportId: z.string().trim().describe(SECRET_IMPORTS.DELETE.secretImportId) + }), + body: z.object({ + workspaceId: z.string().trim().describe(SECRET_IMPORTS.DELETE.projectId), + environment: z.string().trim().describe(SECRET_IMPORTS.DELETE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.DELETE.path) + }), + response: { + 200: z.object({ + message: z.string(), + secretImport: SecretImportsSchema.omit({ importEnv: true }).merge( + z.object({ + importEnv: z.object({ name: z.string(), slug: z.string(), id: z.string() }) + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretImport = await server.services.secretImport.deleteImport({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.secretImportId, + ...req.body, + projectId: req.body.workspaceId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.body.workspaceId, + event: { + type: EventType.DELETE_SECRET_IMPORT, + metadata: { + secretImportId: secretImport.id, + folderId: secretImport.folderId, + importFromEnvironment: secretImport.importEnv.slug, + importFromSecretPath: secretImport.importPath, + importToEnvironment: req.body.environment, + importToSecretPath: req.body.path + } + } + }); + return { message: "Successfully deleted secret import", secretImport }; + } + }); + + server.route({ + method: "POST", + url: "/:secretImportId/replication-resync", + config: { + rateLimit: secretsLimit + }, + schema: { + description: "Resync secret replication of secret imports", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretImportId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.secretImportId) + }), + body: z.object({ + workspaceId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.projectId), + environment: z.string().trim().describe(SECRET_IMPORTS.UPDATE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.UPDATE.path) + }), + response: { + 200: z.object({ + message: z.string() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const { message } = await server.services.secretImport.resyncSecretImportReplication({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.secretImportId, + ...req.body, + projectId: req.body.workspaceId + }); + + return { message }; + } + }); + + server.route({ + method: "GET", + url: "/", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], + description: "Get secret imports", + security: [ + { + bearerAuth: [] + } + ], + querystring: z.object({ + workspaceId: z.string().trim().describe(SECRET_IMPORTS.LIST.projectId), + environment: z.string().trim().describe(SECRET_IMPORTS.LIST.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.LIST.path) + }), + response: { + 200: z.object({ + message: z.string(), + secretImports: SecretImportsSchema.omit({ importEnv: true }) + .extend({ + importEnv: z.object({ name: z.string(), slug: z.string(), id: z.string() }) + }) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretImports = await server.services.secretImport.getImports({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.query, + projectId: req.query.workspaceId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.query.workspaceId, + event: { + type: EventType.GET_SECRET_IMPORTS, + metadata: { + environment: req.query.environment, + folderId: secretImports?.[0]?.folderId, + numberOfImports: secretImports.length + } + } + }); + return { message: "Successfully fetched secret imports", secretImports }; + } + }); + + server.route({ + url: "/:secretImportId", + method: "GET", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], + description: "Get single secret import", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretImportId: z.string().trim().describe(SECRET_IMPORTS.GET.secretImportId) + }), + response: { + 200: z.object({ + secretImport: SecretImportsSchema.omit({ importEnv: true }).extend({ + environment: z.object({ + id: z.string(), + name: z.string(), + slug: z.string() + }), + projectId: z.string(), + importEnv: z.object({ name: z.string(), slug: z.string(), id: z.string() }), + secretPath: z.string() + }) + }) + } + }, + + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretImport = await server.services.secretImport.getImportById({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.secretImportId + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: secretImport.projectId, + event: { + type: EventType.GET_SECRET_IMPORT, + metadata: { + secretImportId: secretImport.id, + folderId: secretImport.folderId + } + } + }); + + return { secretImport }; + } + }); + + server.route({ + url: "/secrets", + method: "GET", + config: { + rateLimit: secretsLimit + }, + schema: { + querystring: z.object({ + workspaceId: z.string().trim(), + environment: z.string().trim(), + path: z.string().trim().default("/").transform(removeTrailingSlash) + }), + response: { + 200: z.object({ + secrets: z + .object({ + secretPath: z.string(), + environment: z.string(), + environmentInfo: z.object({ + id: z.string(), + name: z.string(), + slug: z.string() + }), + folderId: z.string().optional(), + secrets: SecretsSchema.omit({ secretBlindIndex: true }).array() + }) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const importedSecrets = await server.services.secretImport.getSecretsFromImports({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.query, + projectId: req.query.workspaceId + }); + return { secrets: importedSecrets }; + } + }); + + server.route({ + url: "/secrets/raw", + method: "GET", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], + querystring: z.object({ + workspaceId: z.string().trim(), + environment: z.string().trim(), + path: z.string().trim().default("/").transform(removeTrailingSlash) + }), + response: { + 200: z.object({ + secrets: z + .object({ + secretPath: z.string(), + environment: z.string(), + environmentInfo: z.object({ + id: z.string(), + name: z.string(), + slug: z.string() + }), + folderId: z.string().optional(), + secrets: secretRawSchema.array() + }) + .array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const importedSecrets = await server.services.secretImport.getRawSecretsFromImports({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.query, + projectId: req.query.workspaceId + }); + return { secrets: importedSecrets }; + } + }); +}; diff --git a/backend/src/server/routes/v1/deprecated-secret-tag-router.ts b/backend/src/server/routes/v1/deprecated-secret-tag-router.ts new file mode 100644 index 000000000..d90475408 --- /dev/null +++ b/backend/src/server/routes/v1/deprecated-secret-tag-router.ts @@ -0,0 +1,213 @@ +import { z } from "zod"; + +import { SecretTagsSchema } from "@app/db/schemas"; +import { ApiDocsTags, SECRET_TAGS } from "@app/lib/api-docs"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { slugSchema } from "@app/server/lib/schemas"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; + +export const registerDeprecatedSecretTagRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "GET", + url: "/:projectId/tags", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + params: z.object({ + projectId: z.string().trim().describe(SECRET_TAGS.LIST.projectId) + }), + response: { + 200: z.object({ + workspaceTags: SecretTagsSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaceTags = await server.services.secretTag.getProjectTags({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId + }); + return { workspaceTags }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/tags/:tagId", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + params: z.object({ + projectId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_ID.projectId), + tagId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_ID.tagId) + }), + response: { + 200: z.object({ + // akhilmhdh: for terraform backward compatiability + workspaceTag: SecretTagsSchema.extend({ name: z.string() }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaceTag = await server.services.secretTag.getTagById({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.tagId + }); + return { workspaceTag }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/tags/slug/:tagSlug", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + params: z.object({ + projectId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_SLUG.projectId), + tagSlug: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_SLUG.tagSlug) + }), + response: { + 200: z.object({ + // akhilmhdh: for terraform backward compatiability + workspaceTag: SecretTagsSchema.extend({ name: z.string() }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaceTag = await server.services.secretTag.getTagBySlug({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + slug: req.params.tagSlug, + projectId: req.params.projectId + }); + return { workspaceTag }; + } + }); + + server.route({ + method: "POST", + url: "/:projectId/tags", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + params: z.object({ + projectId: z.string().trim().describe(SECRET_TAGS.CREATE.projectId) + }), + body: z.object({ + slug: slugSchema({ max: 64 }).describe(SECRET_TAGS.CREATE.slug), + color: z.string().trim().describe(SECRET_TAGS.CREATE.color) + }), + response: { + 200: z.object({ + workspaceTag: SecretTagsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaceTag = await server.services.secretTag.createTag({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + ...req.body + }); + return { workspaceTag }; + } + }); + + server.route({ + method: "PATCH", + url: "/:projectId/tags/:tagId", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + params: z.object({ + projectId: z.string().trim().describe(SECRET_TAGS.UPDATE.projectId), + tagId: z.string().trim().describe(SECRET_TAGS.UPDATE.tagId) + }), + body: z.object({ + slug: slugSchema({ max: 64 }).describe(SECRET_TAGS.UPDATE.slug), + color: z.string().trim().describe(SECRET_TAGS.UPDATE.color) + }), + response: { + 200: z.object({ + workspaceTag: SecretTagsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaceTag = await server.services.secretTag.updateTag({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body, + id: req.params.tagId + }); + return { workspaceTag }; + } + }); + + server.route({ + method: "DELETE", + url: "/:projectId/tags/:tagId", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Folders], + params: z.object({ + projectId: z.string().trim().describe(SECRET_TAGS.DELETE.projectId), + tagId: z.string().trim().describe(SECRET_TAGS.DELETE.tagId) + }), + response: { + 200: z.object({ + workspaceTag: SecretTagsSchema + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const workspaceTag = await server.services.secretTag.deleteTag({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + id: req.params.tagId + }); + return { workspaceTag }; + } + }); +}; diff --git a/backend/src/server/routes/v2/group-project-router.ts b/backend/src/server/routes/v1/group-project-router.ts similarity index 100% rename from backend/src/server/routes/v2/group-project-router.ts rename to backend/src/server/routes/v1/group-project-router.ts diff --git a/backend/src/server/routes/v2/identity-project-router.ts b/backend/src/server/routes/v1/identity-project-router.ts similarity index 100% rename from backend/src/server/routes/v2/identity-project-router.ts rename to backend/src/server/routes/v1/identity-project-router.ts diff --git a/backend/src/server/routes/v1/index.ts b/backend/src/server/routes/v1/index.ts index 6108be32b..4fb07aeac 100644 --- a/backend/src/server/routes/v1/index.ts +++ b/backend/src/server/routes/v1/index.ts @@ -13,8 +13,15 @@ import { registerCaRouter } from "./certificate-authority-router"; import { CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP } from "./certificate-authority-routers"; import { registerCertRouter } from "./certificate-router"; import { registerCertificateTemplateRouter } from "./certificate-template-router"; +import { registerDeprecatedProjectEnvRouter } from "./deprecated-project-env-router"; +import { registerDeprecatedProjectMembershipRouter } from "./deprecated-project-membership-router"; +import { registerDeprecatedProjectRouter } from "./deprecated-project-router"; +import { registerDeprecatedSecretFolderRouter } from "./deprecated-secret-folder-router"; +import { registerDeprecatedSecretImportRouter } from "./deprecated-secret-import-router"; +import { registerDeprecatedSecretTagRouter } from "./deprecated-secret-tag-router"; import { registerEventRouter } from "./event-router"; import { registerExternalGroupOrgRoleMappingRouter } from "./external-group-org-role-mapping-router"; +import { registerGroupProjectRouter } from "./group-project-router"; import { registerIdentityAccessTokenRouter } from "./identity-access-token-router"; import { registerIdentityAliCloudAuthRouter } from "./identity-alicloud-auth-router"; import { registerIdentityAwsAuthRouter } from "./identity-aws-iam-auth-router"; @@ -25,6 +32,7 @@ import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-rou import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router"; import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router"; import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router"; +import { registerIdentityProjectRouter } from "./identity-project-router"; import { registerIdentityRouter } from "./identity-router"; import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router"; import { registerIdentityTokenAuthRouter } from "./identity-token-auth-router"; @@ -45,8 +53,6 @@ import { registerProjectKeyRouter } from "./project-key-router"; import { registerProjectMembershipRouter } from "./project-membership-router"; import { registerProjectRouter } from "./project-router"; import { SECRET_REMINDER_REGISTER_ROUTER_MAP } from "./reminder-routers"; -import { registerSecretFolderRouter } from "./secret-folder-router"; -import { registerSecretImportRouter } from "./secret-import-router"; import { registerSecretRequestsRouter } from "./secret-requests-router"; import { registerSecretSharingRouter } from "./secret-sharing-router"; import { registerSecretTagRouter } from "./secret-tag-router"; @@ -87,8 +93,8 @@ export const registerV1Routes = async (server: FastifyZodProvider) => { await server.register(registerNotificationRouter, { prefix: "/notifications" }); await server.register(registerInviteOrgRouter, { prefix: "/invite-org" }); await server.register(registerUserActionRouter, { prefix: "/user-action" }); - await server.register(registerSecretImportRouter, { prefix: "/secret-imports" }); - await server.register(registerSecretFolderRouter, { prefix: "/folders" }); + await server.register(registerDeprecatedSecretImportRouter, { prefix: "/secret-imports" }); + await server.register(registerDeprecatedSecretFolderRouter, { prefix: "/folders" }); await server.register( async (workflowIntegrationRouter) => { @@ -101,15 +107,28 @@ export const registerV1Routes = async (server: FastifyZodProvider) => { await server.register( async (projectRouter) => { - await projectRouter.register(registerProjectRouter); - await projectRouter.register(registerProjectEnvRouter); + await projectRouter.register(registerDeprecatedProjectRouter); + await projectRouter.register(registerDeprecatedProjectEnvRouter); + // depreciated completed in use await projectRouter.register(registerProjectKeyRouter); - await projectRouter.register(registerProjectMembershipRouter); - await projectRouter.register(registerSecretTagRouter); + await projectRouter.register(registerDeprecatedProjectMembershipRouter); + await projectRouter.register(registerDeprecatedSecretTagRouter); }, { prefix: "/workspace" } ); + await server.register( + async (projectRouter) => { + await projectRouter.register(registerProjectRouter); + await projectRouter.register(registerProjectMembershipRouter); + await projectRouter.register(registerProjectEnvRouter); + await projectRouter.register(registerSecretTagRouter); + await projectRouter.register(registerGroupProjectRouter); + await projectRouter.register(registerIdentityProjectRouter); + }, + { prefix: "/projects" } + ); + await server.register( async (pkiRouter) => { await pkiRouter.register(registerCaRouter, { prefix: "/ca" }); diff --git a/backend/src/server/routes/v1/project-env-router.ts b/backend/src/server/routes/v1/project-env-router.ts index 9a136e160..81b828b55 100644 --- a/backend/src/server/routes/v1/project-env-router.ts +++ b/backend/src/server/routes/v1/project-env-router.ts @@ -11,58 +11,7 @@ import { AuthMode } from "@app/services/auth/auth-type"; export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/environments/:envId", - config: { - rateLimit: readLimit - }, - schema: { - hide: false, - tags: [ApiDocsTags.Environments], - description: "Get Environment", - security: [ - { - bearerAuth: [] - } - ], - params: z.object({ - // NOTE(daniel): workspaceId isn't used, but we need to keep it for backwards compatibility. The endpoint defined below, uses no project ID, and is takes a pure environment ID. - workspaceId: z.string().trim().describe(ENVIRONMENTS.GET.workspaceId), - envId: z.string().trim().describe(ENVIRONMENTS.GET.id) - }), - response: { - 200: z.object({ - environment: ProjectEnvironmentsSchema - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), - handler: async (req) => { - const environment = await server.services.projectEnv.getEnvironmentById({ - actorId: req.permission.id, - actor: req.permission.type, - actorOrgId: req.permission.orgId, - actorAuthMethod: req.permission.authMethod, - id: req.params.envId - }); - - await server.services.auditLog.createAuditLog({ - ...req.auditLogInfo, - projectId: environment.projectId, - event: { - type: EventType.GET_ENVIRONMENT, - metadata: { - id: environment.id - } - } - }); - - return { environment }; - } - }); - - server.route({ - method: "GET", - url: "/environments/:envId", + url: "/:projectId/environments/:envId", config: { rateLimit: readLimit }, @@ -76,7 +25,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - envId: z.string().trim().describe(ENVIRONMENTS.GET.id) + envId: z.string().trim().describe(ENVIRONMENTS.GET.id), + projectId: z.string().trim().describe(ENVIRONMENTS.GET.projectId) }), response: { 200: z.object({ @@ -111,7 +61,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/:workspaceId/environments", + url: "/:projectId/environments", config: { rateLimit: writeLimit }, @@ -125,7 +75,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(ENVIRONMENTS.CREATE.workspaceId) + projectId: z.string().trim().describe(ENVIRONMENTS.CREATE.projectId) }), body: z.object({ name: z.string().trim().describe(ENVIRONMENTS.CREATE.name), @@ -135,7 +85,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ message: z.string(), - workspace: z.string(), + projectId: z.string(), environment: ProjectEnvironmentsSchema }) } @@ -147,7 +97,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { actor: req.permission.type, actorOrgId: req.permission.orgId, actorAuthMethod: req.permission.authMethod, - projectId: req.params.workspaceId, + projectId: req.params.projectId, ...req.body }); @@ -164,7 +114,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { }); return { message: "Successfully created new environment", - workspace: req.params.workspaceId, + projectId: req.params.projectId, environment }; } @@ -172,7 +122,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { server.route({ method: "PATCH", - url: "/:workspaceId/environments/:id", + url: "/:projectId/environments/:id", config: { rateLimit: writeLimit }, @@ -186,7 +136,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(ENVIRONMENTS.UPDATE.workspaceId), + projectId: z.string().trim().describe(ENVIRONMENTS.UPDATE.projectId), id: z.string().trim().describe(ENVIRONMENTS.UPDATE.id) }), body: z.object({ @@ -197,7 +147,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ message: z.string(), - workspace: z.string(), + projectId: z.string(), environment: ProjectEnvironmentsSchema }) } @@ -209,7 +159,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, id: req.params.id, ...req.body }); @@ -232,7 +182,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { return { message: "Successfully updated environment", - workspace: req.params.workspaceId, + projectId: req.params.projectId, environment }; } @@ -240,7 +190,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { server.route({ method: "DELETE", - url: "/:workspaceId/environments/:id", + url: "/:projectId/environments/:id", config: { rateLimit: writeLimit }, @@ -254,13 +204,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(ENVIRONMENTS.DELETE.workspaceId), + projectId: z.string().trim().describe(ENVIRONMENTS.DELETE.projectId), id: z.string().trim().describe(ENVIRONMENTS.DELETE.id) }), response: { 200: z.object({ message: z.string(), - workspace: z.string(), + projectId: z.string(), environment: ProjectEnvironmentsSchema }) } @@ -272,7 +222,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, id: req.params.id }); @@ -290,7 +240,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { return { message: "Successfully deleted environment", - workspace: req.params.workspaceId, + projectId: req.params.projectId, environment }; } diff --git a/backend/src/server/routes/v1/project-membership-router.ts b/backend/src/server/routes/v1/project-membership-router.ts index cd3734efc..f3cdfe701 100644 --- a/backend/src/server/routes/v1/project-membership-router.ts +++ b/backend/src/server/routes/v1/project-membership-router.ts @@ -1,7 +1,8 @@ import { z } from "zod"; import { - OrgMembershipsSchema, + OrgMembershipRole, + ProjectMembershipRole, ProjectMembershipsSchema, ProjectUserMembershipRolesSchema, UserEncryptionKeysSchema, @@ -18,7 +19,7 @@ import { ProjectUserMembershipTemporaryMode } from "@app/services/project-member export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/memberships", + url: "/:projectId/memberships", config: { rateLimit: readLimit }, @@ -32,7 +33,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIPS.workspaceId) + projectId: z.string().trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIPS.projectId) }), response: { 200: z.object({ @@ -71,7 +72,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return { memberships }; } @@ -79,7 +80,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider server.route({ method: "GET", - url: "/:workspaceId/memberships/:membershipId", + url: "/:projectId/memberships/:membershipId", config: { rateLimit: readLimit }, @@ -91,7 +92,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.workspaceId), + projectId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.projectId), membershipId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.membershipId) }), response: { @@ -129,7 +130,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, id: req.params.membershipId }); return { membership }; @@ -138,7 +139,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider server.route({ method: "POST", - url: "/:workspaceId/memberships/details", + url: "/:projectId/memberships/details", config: { rateLimit: readLimit }, @@ -152,7 +153,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.workspaceId) + projectId: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.projectId) }), body: z.object({ username: z.string().min(1).trim().describe(PROJECT_USERS.GET_USER_MEMBERSHIP.username) @@ -191,7 +192,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, username: req.body.username }); return { membership }; @@ -200,61 +201,83 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider server.route({ method: "POST", - url: "/:workspaceId/memberships", + url: "/:projectId/memberships", config: { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], + description: "Invite members to project", + security: [ + { + bearerAuth: [] + } + ], params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().describe(PROJECT_USERS.INVITE_MEMBER.projectId) }), body: z.object({ - members: z - .object({ - orgMembershipId: z.string().trim(), - workspaceEncryptedKey: z.string().trim(), - workspaceEncryptedNonce: z.string().trim() - }) + emails: z + .string() + .email() .array() - .min(1) + .default([]) + .describe(PROJECT_USERS.INVITE_MEMBER.emails) + .refine((val) => val.every((el) => el === el.toLowerCase()), "Email must be lowercase"), + usernames: z + .string() + .array() + .default([]) + .describe(PROJECT_USERS.INVITE_MEMBER.usernames) + .refine((val) => val.every((el) => el === el.toLowerCase()), "Username must be lowercase"), + roleSlugs: z.string().array().min(1).optional().describe(PROJECT_USERS.INVITE_MEMBER.roleSlugs) }), response: { 200: z.object({ - success: z.boolean(), - data: OrgMembershipsSchema.array() + memberships: ProjectMembershipsSchema.array() }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const data = await server.services.projectMembership.addUsersToProject({ - actorId: req.permission.id, - actor: req.permission.type, + const usernamesAndEmails = [...req.body.emails, ...req.body.usernames]; + const { projectMemberships: memberships } = await server.services.org.inviteUserToOrganization({ actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, - members: req.body.members + actor: req.permission.type, + inviteeEmails: usernamesAndEmails, + orgId: req.permission.orgId, + organizationRoleSlug: OrgMembershipRole.NoAccess, + projects: [ + { + id: req.params.projectId, + projectRoleSlug: req.body.roleSlugs || [ProjectMembershipRole.Member] + } + ] }); await server.services.auditLog.createAuditLog({ - projectId: req.params.workspaceId, + projectId: req.params.projectId, ...req.auditLogInfo, event: { - type: EventType.ADD_BATCH_WORKSPACE_MEMBER, - metadata: data.map(({ userId }) => ({ + type: EventType.ADD_BATCH_PROJECT_MEMBER, + metadata: memberships.map(({ userId, id }) => ({ userId: userId || "", + membershipId: id, email: "" })) } }); - return { data, success: true }; + return { memberships }; } }); server.route({ method: "PATCH", - url: "/:workspaceId/memberships/:membershipId", + url: "/:projectId/memberships/:membershipId", config: { rateLimit: writeLimit }, @@ -268,7 +291,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECT_USERS.UPDATE_USER_MEMBERSHIP.workspaceId), + projectId: z.string().trim().describe(PROJECT_USERS.UPDATE_USER_MEMBERSHIP.projectId), membershipId: z.string().trim().describe(PROJECT_USERS.UPDATE_USER_MEMBERSHIP.membershipId) }), body: z.object({ @@ -305,31 +328,87 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, membershipId: req.params.membershipId, roles: req.body.roles }); - // await server.services.auditLog.createAuditLog({ - // ...req.auditLogInfo, - // projectId: req.params.workspaceId, - // event: { - // type: EventType.UPDATE_USER_WORKSPACE_ROLE, - // metadata: { - // userId: membership.userId, - // newRole: req.body.role, - // oldRole: membership.role, - // email: "" - // } - // } - // }); return { roles }; } }); server.route({ method: "DELETE", - url: "/:workspaceId/memberships/:membershipId", + url: "/:projectId/memberships", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], + description: "Remove members from project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().describe(PROJECT_USERS.REMOVE_MEMBER.projectId) + }), + body: z.object({ + emails: z + .string() + .email() + .array() + .default([]) + .describe(PROJECT_USERS.REMOVE_MEMBER.emails) + .refine((val) => val.every((el) => el === el.toLowerCase()), "Email must be lowercase"), + usernames: z + .string() + .array() + .default([]) + .describe(PROJECT_USERS.REMOVE_MEMBER.usernames) + .refine((val) => val.every((el) => el === el.toLowerCase()), "Username must be lowercase") + }), + response: { + 200: z.object({ + memberships: ProjectMembershipsSchema.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const memberships = await server.services.projectMembership.deleteProjectMemberships({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + emails: req.body.emails, + usernames: req.body.usernames + }); + + for (const membership of memberships) { + // eslint-disable-next-line no-await-in-loop + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.params.projectId, + event: { + type: EventType.REMOVE_PROJECT_MEMBER, + metadata: { + userId: membership.userId, + email: "" + } + } + }); + } + return { memberships }; + } + }); + + server.route({ + method: "DELETE", + url: "/:projectId/memberships/:membershipId", config: { rateLimit: writeLimit }, @@ -341,7 +420,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), membershipId: z.string().trim() }), response: { @@ -357,15 +436,15 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, membershipId: req.params.membershipId }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { - type: EventType.REMOVE_WORKSPACE_MEMBER, + type: EventType.REMOVE_PROJECT_MEMBER, metadata: { userId: membership.userId, email: "" @@ -378,13 +457,13 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider server.route({ method: "DELETE", - url: "/:workspaceId/leave", + url: "/:projectId/leave", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -398,7 +477,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider const membership = await server.services.projectMembership.leaveProject({ actorId: req.permission.id, actor: req.permission.type, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return { membership }; } diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index 5c5af7523..be8b46dd5 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -2,7 +2,10 @@ import slugify from "@sindresorhus/slugify"; import { z } from "zod"; import { + CertificatesSchema, IntegrationsSchema, + PkiAlertsSchema, + PkiCollectionsSchema, ProjectEnvironmentsSchema, ProjectMembershipsSchema, ProjectRolesSchema, @@ -16,18 +19,35 @@ import { } from "@app/db/schemas"; import { ProjectMicrosoftTeamsConfigsSchema } from "@app/db/schemas/project-microsoft-teams-configs"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { InfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-types"; +import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-schema"; +import { sanitizedSshCertificate } from "@app/ee/services/ssh-certificate/ssh-certificate-schema"; +import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema"; +import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema"; +import { LoginMappingSource } from "@app/ee/services/ssh-host/ssh-host-types"; +import { sanitizedSshHostGroup } from "@app/ee/services/ssh-host-group/ssh-host-group-schema"; import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; import { CharacterType, characterValidator } from "@app/lib/validator/validate-string"; import { re2Validator } from "@app/lib/zod"; import { readLimit, requestAccessLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { slugSchema } from "@app/server/lib/schemas"; +import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { ActorType, AuthMode } from "@app/services/auth/auth-type"; +import { CaStatus } from "@app/services/certificate-authority/certificate-authority-enums"; +import { sanitizedCertificateTemplate } from "@app/services/certificate-template/certificate-template-schema"; import { validateMicrosoftTeamsChannelsSchema } from "@app/services/microsoft-teams/microsoft-teams-fns"; +import { sanitizedPkiSubscriber } from "@app/services/pki-subscriber/pki-subscriber-schema"; import { ProjectFilterType, SearchProjectSortBy } from "@app/services/project/project-types"; import { validateSlackChannelsField } from "@app/services/slack/slack-auth-validators"; +import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; import { WorkflowIntegration } from "@app/services/workflow-integration/workflow-integration-types"; -import { integrationAuthPubSchema, SanitizedProjectSchema } from "../sanitizedSchemas"; +import { + integrationAuthPubSchema, + InternalCertificateAuthorityResponseSchema, + SanitizedProjectSchema +} from "../sanitizedSchemas"; import { sanitizedServiceTokenSchema } from "../v2/service-token-router"; const projectWithEnv = SanitizedProjectSchema.merge( @@ -40,41 +60,7 @@ const projectWithEnv = SanitizedProjectSchema.merge( export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/keys", - config: { - rateLimit: readLimit - }, - schema: { - params: z.object({ - workspaceId: z.string().trim() - }), - response: { - 200: z.object({ - publicKeys: z - .object({ - publicKey: z.string().nullable().optional(), - userId: z.string() - }) - .array() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const publicKeys = await server.services.projectKey.getProjectPublicKeys({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId - }); - return { publicKeys }; - } - }); - - server.route({ - method: "GET", - url: "/:workspaceId/users", + url: "/:projectId/users", config: { rateLimit: readLimit }, @@ -96,7 +82,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { .optional() }), params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -142,7 +128,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actor: req.permission.type, actorAuthMethod: req.permission.authMethod, includeGroupMembers: req.query.includeGroupMembers, - projectId: req.params.workspaceId, + projectId: req.params.projectId, actorOrgId: req.permission.orgId, roles }); @@ -151,6 +137,83 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } }); + server.route({ + method: "POST", + url: "/", + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "Create a new project", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + projectName: z.string().trim().describe(PROJECTS.CREATE.projectName), + projectDescription: z.string().trim().optional().describe(PROJECTS.CREATE.projectDescription), + slug: slugSchema({ min: 5, max: 36 }).optional().describe(PROJECTS.CREATE.slug), + kmsKeyId: z.string().optional(), + template: slugSchema({ field: "Template Name", max: 64 }) + .optional() + .default(InfisicalProjectTemplate.Default) + .describe(PROJECTS.CREATE.template), + type: z.nativeEnum(ProjectType).default(ProjectType.SecretManager), + shouldCreateDefaultEnvs: z.boolean().optional().default(true) + }), + response: { + 200: z.object({ + project: projectWithEnv + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const project = await server.services.project.createProject({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + projectName: req.body.projectName, + projectDescription: req.body.projectDescription, + slug: req.body.slug, + kmsKeyId: req.body.kmsKeyId, + template: req.body.template, + type: req.body.type, + createDefaultEnvs: req.body.shouldCreateDefaultEnvs + }); + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.ProjectCreated, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + orgId: project.orgId, + name: project.name, + ...req.auditLogInfo + } + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: project.id, + event: { + type: EventType.CREATE_PROJECT, + metadata: { + ...req.body, + name: req.body.projectName + } + } + }); + + return { project }; + } + }); + server.route({ method: "GET", url: "/", @@ -158,6 +221,14 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "List projects", + security: [ + { + bearerAuth: [] + } + ], querystring: z.object({ includeRoles: z .enum(["true", "false"]) @@ -167,7 +238,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - workspaces: projectWithEnv + projects: projectWithEnv .extend({ roles: ProjectRolesSchema.array().optional() }) @@ -177,7 +248,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaces = await server.services.project.getProjects({ + const projects = await server.services.project.getProjects({ includeRoles: req.query.includeRoles, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -185,13 +256,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorOrgId: req.permission.orgId, type: req.query.type }); - return { workspaces }; + return { projects }; } }); server.route({ method: "GET", - url: "/:workspaceId", + url: "/:projectId", config: { rateLimit: readLimit }, @@ -205,33 +276,73 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.GET.workspaceId) + projectId: z.string().trim().describe(PROJECTS.GET.projectId) }), response: { 200: z.object({ - workspace: projectWithEnv.optional() + project: projectWithEnv.optional() }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspace = await server.services.project.getAProject({ + const project = await server.services.project.getAProject({ filter: { type: ProjectFilterType.ID, - projectId: req.params.workspaceId + projectId: req.params.projectId }, actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, actor: req.permission.type, actorOrgId: req.permission.orgId }); - return { workspace }; + return { project }; + } + }); + + server.route({ + method: "GET", + url: "/slug/:slug", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Projects], + description: "Get project details by slug", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + slug: slugSchema({ max: 36 }).describe("The slug of the project to get.") + }), + response: { + 200: projectWithEnv + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const project = await server.services.project.getAProject({ + filter: { + slug: req.params.slug, + orgId: req.permission.orgId, + type: ProjectFilterType.SLUG + }, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type + }); + + return project; } }); server.route({ method: "DELETE", - url: "/:workspaceId", + url: "/:projectId", config: { rateLimit: writeLimit }, @@ -245,20 +356,20 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.DELETE.workspaceId) + projectId: z.string().trim().describe(PROJECTS.DELETE.projectId) }), response: { 200: z.object({ - workspace: SanitizedProjectSchema.optional() + project: SanitizedProjectSchema.optional() }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspace = await server.services.project.deleteProject({ + const project = await server.services.project.deleteProject({ filter: { type: ProjectFilterType.ID, - projectId: req.params.workspaceId + projectId: req.params.projectId }, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -269,68 +380,20 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, orgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.DELETE_PROJECT, - metadata: workspace + metadata: project } }); - return { workspace }; - } - }); - - server.route({ - url: "/:workspaceId/name", - method: "POST", - config: { - rateLimit: writeLimit - }, - schema: { - params: z.object({ - workspaceId: z.string().trim() - }), - body: z.object({ - name: z.string().trim() - }), - response: { - 200: z.object({ - message: z.string(), - workspace: SanitizedProjectSchema - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const workspace = await server.services.project.updateName({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, - name: req.body.name - }); - - await server.services.auditLog.createAuditLog({ - ...req.auditLogInfo, - orgId: req.permission.orgId, - projectId: req.params.workspaceId, - event: { - type: EventType.UPDATE_PROJECT, - metadata: req.body - } - }); - - return { - message: "Successfully changed workspace name", - workspace - }; + return { project }; } }); server.route({ method: "PATCH", - url: "/:workspaceId", + url: "/:projectId", config: { rateLimit: writeLimit }, @@ -344,7 +407,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.UPDATE.workspaceId) + projectId: z.string().trim().describe(PROJECTS.UPDATE.projectId) }), body: z.object({ name: z @@ -373,35 +436,35 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { .describe(PROJECTS.UPDATE.slug), secretSharing: z.boolean().optional().describe(PROJECTS.UPDATE.secretSharing), showSnapshotsLegacy: z.boolean().optional().describe(PROJECTS.UPDATE.showSnapshotsLegacy), - defaultProduct: z.nativeEnum(ProjectType).optional().describe(PROJECTS.UPDATE.defaultProduct), secretDetectionIgnoreValues: z .array(z.string()) .optional() - .describe(PROJECTS.UPDATE.secretDetectionIgnoreValues) + .describe(PROJECTS.UPDATE.secretDetectionIgnoreValues), + pitVersionLimit: z.number().min(1).max(100).optional() }), response: { 200: z.object({ - workspace: SanitizedProjectSchema + project: SanitizedProjectSchema }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspace = await server.services.project.updateProject({ + const project = await server.services.project.updateProject({ filter: { type: ProjectFilterType.ID, - projectId: req.params.workspaceId + projectId: req.params.projectId }, update: { name: req.body.name, description: req.body.description, autoCapitalization: req.body.autoCapitalization, - defaultProduct: req.body.defaultProduct, hasDeleteProtection: req.body.hasDeleteProtection, slug: req.body.slug, secretSharing: req.body.secretSharing, showSnapshotsLegacy: req.body.showSnapshotsLegacy, - secretDetectionIgnoreValues: req.body.secretDetectionIgnoreValues + secretDetectionIgnoreValues: req.body.secretDetectionIgnoreValues, + pitVersionLimit: req.body.pitVersionLimit }, actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -412,7 +475,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, orgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.UPDATE_PROJECT, metadata: req.body @@ -420,164 +483,20 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { }); return { - workspace - }; - } - }); - - server.route({ - method: "POST", - url: "/:workspaceId/auto-capitalization", - config: { - rateLimit: writeLimit - }, - schema: { - params: z.object({ - workspaceId: z.string().trim() - }), - body: z.object({ - autoCapitalization: z.boolean() - }), - response: { - 200: z.object({ - message: z.string(), - workspace: SanitizedProjectSchema - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const workspace = await server.services.project.toggleAutoCapitalization({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, - autoCapitalization: req.body.autoCapitalization - }); - - await server.services.auditLog.createAuditLog({ - ...req.auditLogInfo, - orgId: req.permission.orgId, - projectId: req.params.workspaceId, - event: { - type: EventType.UPDATE_PROJECT, - metadata: req.body - } - }); - - return { - message: "Successfully changed workspace settings", - workspace - }; - } - }); - - server.route({ - method: "POST", - url: "/:workspaceId/delete-protection", - config: { - rateLimit: writeLimit - }, - schema: { - params: z.object({ - workspaceId: z.string().trim() - }), - body: z.object({ - hasDeleteProtection: z.boolean() - }), - response: { - 200: z.object({ - message: z.string(), - workspace: SanitizedProjectSchema - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const workspace = await server.services.project.toggleDeleteProtection({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, - hasDeleteProtection: req.body.hasDeleteProtection - }); - - await server.services.auditLog.createAuditLog({ - ...req.auditLogInfo, - orgId: req.permission.orgId, - projectId: req.params.workspaceId, - event: { - type: EventType.UPDATE_PROJECT, - metadata: req.body - } - }); - - return { - message: "Successfully changed workspace settings", - workspace + project }; } }); server.route({ method: "PUT", - url: "/:workspaceSlug/version-limit", + url: "/:projectId/audit-logs-retention", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceSlug: z.string().trim() - }), - body: z.object({ - pitVersionLimit: z.number().min(1).max(100) - }), - response: { - 200: z.object({ - message: z.string(), - workspace: SanitizedProjectSchema - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const workspace = await server.services.project.updateVersionLimit({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - pitVersionLimit: req.body.pitVersionLimit, - workspaceSlug: req.params.workspaceSlug - }); - - await server.services.auditLog.createAuditLog({ - ...req.auditLogInfo, - orgId: req.permission.orgId, - projectId: workspace.id, - event: { - type: EventType.UPDATE_PROJECT, - metadata: req.body - } - }); - - return { - message: "Successfully changed workspace version limit", - workspace - }; - } - }); - - server.route({ - method: "PUT", - url: "/:workspaceSlug/audit-logs-retention", - config: { - rateLimit: writeLimit - }, - schema: { - params: z.object({ - workspaceSlug: z.string().trim() + projectId: z.string().trim() }), body: z.object({ auditLogsRetentionDays: z.number().min(0) @@ -585,25 +504,28 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ message: z.string(), - workspace: SanitizedProjectSchema + project: SanitizedProjectSchema }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspace = await server.services.project.updateAuditLogsRetention({ + const project = await server.services.project.updateAuditLogsRetention({ actorId: req.permission.id, actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - workspaceSlug: req.params.workspaceSlug, - auditLogsRetentionDays: req.body.auditLogsRetentionDays + auditLogsRetentionDays: req.body.auditLogsRetentionDays, + filter: { + projectId: req.params.projectId, + type: ProjectFilterType.ID + } }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, orgId: req.permission.orgId, - projectId: workspace.id, + projectId: project.id, event: { type: EventType.UPDATE_PROJECT, metadata: req.body @@ -612,14 +534,14 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { return { message: "Successfully updated project's audit logs retention period", - workspace + project }; } }); server.route({ method: "GET", - url: "/:workspaceId/integrations", + url: "/:projectId/integrations", config: { rateLimit: readLimit }, @@ -633,7 +555,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION.workspaceId) + projectId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION.projectId) }), response: { 200: z.object({ @@ -656,7 +578,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return { integrations }; } @@ -664,21 +586,21 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/authorizations", + url: "/:projectId/authorizations", config: { rateLimit: readLimit }, schema: { hide: false, tags: [ApiDocsTags.Integrations], - description: "List integration auth objects for a workspace.", + description: "List integration auth objects for a project.", security: [ { bearerAuth: [] } ], params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION_AUTHORIZATION.workspaceId) + projectId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION_AUTHORIZATION.projectId) }), response: { 200: z.object({ @@ -693,7 +615,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return { authorizations }; } @@ -701,13 +623,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/service-token-data", + url: "/:projectId/service-token-data", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.object({ @@ -722,7 +644,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); return { serviceTokenData }; } @@ -730,13 +652,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/ssh-config", + url: "/:projectId/ssh-config", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: ProjectSshConfigsSchema.pick({ @@ -756,7 +678,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId + projectId: req.params.projectId }); await server.services.auditLog.createAuditLog({ @@ -777,13 +699,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "PATCH", - url: "/:workspaceId/ssh-config", + url: "/:projectId/ssh-config", config: { rateLimit: writeLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), body: z.object({ defaultUserSshCaId: z.string().optional(), @@ -807,7 +729,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, ...req.body }); @@ -831,13 +753,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/workflow-integration-config/:integration", + url: "/:projectId/workflow-integration-config/:integration", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), integration: z.nativeEnum(WorkflowIntegration) }), response: { @@ -876,13 +798,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, integration: req.params.integration }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.GET_PROJECT_WORKFLOW_INTEGRATION_CONFIG, metadata: { @@ -936,15 +858,14 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "PUT", - url: "/:workspaceId/workflow-integration", + url: "/:projectId/workflow-integration", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), - body: z.discriminatedUnion("integration", [ z.object({ integration: z.literal(WorkflowIntegration.SLACK), @@ -999,13 +920,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actor: req.permission.type, actorOrgId: req.permission.orgId, - projectId: req.params.workspaceId, + projectId: req.params.projectId, ...req.body }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.UPDATE_PROJECT_WORKFLOW_INTEGRATION_CONFIG, metadata: { @@ -1026,13 +947,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", - url: "/:workspaceId/environment-folder-tree", + url: "/:projectId/environment-folder-tree", config: { rateLimit: readLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), response: { 200: z.record( @@ -1043,7 +964,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { const environmentsFolders = await server.services.folder.getProjectEnvironmentsFolders( - req.params.workspaceId, + req.params.projectId, req.permission ); @@ -1093,13 +1014,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", - url: "/:workspaceId/project-access", + url: "/:projectId/project-access", config: { rateLimit: requestAccessLimit }, schema: { params: z.object({ - workspaceId: z.string().trim() + projectId: z.string().trim() }), body: z.object({ comment: z @@ -1133,17 +1054,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { await server.services.project.requestProjectAccess({ permission: req.permission, comment: req.body.comment, - projectId: req.params.workspaceId + projectId: req.params.projectId }); if (req.auth.actor === ActorType.USER) { await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.params.workspaceId, + projectId: req.params.projectId, event: { type: EventType.PROJECT_ACCESS_REQUEST, metadata: { - projectId: req.params.workspaceId, + projectId: req.params.projectId, requesterEmail: req.auth.user.email || req.auth.user.username, requesterId: req.auth.userId } @@ -1154,4 +1075,456 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { return { message: "Project access request has been send to project admins" }; } }); + + /* Start upgrade of a project */ + server.route({ + method: "POST", + url: "/:projectId/upgrade", + config: { + rateLimit: writeLimit + }, + schema: { + params: z.object({ + projectId: z.string().trim() + }), + body: z.object({ + userPrivateKey: z.string().trim() + }), + response: { + 200: z.void() + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + await server.services.project.upgradeProject({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + projectId: req.params.projectId, + userPrivateKey: req.body.userPrivateKey + }); + } + }); + + /* Get upgrade status of project */ + server.route({ + url: "/:projectId/upgrade/status", + method: "GET", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + projectId: z.string().trim() + }), + response: { + 200: z.object({ + status: z.string().nullable() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const status = await server.services.project.getProjectUpgradeStatus({ + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + actor: req.permission.type, + actorId: req.permission.id + }); + + return { status }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/cas", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], + params: z.object({ + projectId: z.string().trim() + }), + querystring: z.object({ + status: z.enum([CaStatus.ACTIVE, CaStatus.PENDING_CERTIFICATE]).optional().describe(PROJECTS.LIST_CAS.status), + friendlyName: z.string().optional().describe(PROJECTS.LIST_CAS.friendlyName), + commonName: z.string().optional().describe(PROJECTS.LIST_CAS.commonName), + offset: z.coerce.number().min(0).max(100).default(0).describe(PROJECTS.LIST_CAS.offset), + limit: z.coerce.number().min(1).max(100).default(25).describe(PROJECTS.LIST_CAS.limit) + }), + response: { + 200: z.object({ + cas: z.array(InternalCertificateAuthorityResponseSchema) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const cas = await server.services.project.listProjectCas({ + filter: { + projectId: req.params.projectId, + type: ProjectFilterType.ID + }, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + ...req.query + }); + return { cas }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/certificates", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], + params: z.object({ + projectId: z.string().trim() + }), + querystring: z.object({ + friendlyName: z.string().optional().describe(PROJECTS.LIST_CERTIFICATES.friendlyName), + commonName: z.string().optional().describe(PROJECTS.LIST_CERTIFICATES.commonName), + offset: z.coerce.number().min(0).max(100).default(0).describe(PROJECTS.LIST_CERTIFICATES.offset), + limit: z.coerce.number().min(1).max(100).default(25).describe(PROJECTS.LIST_CERTIFICATES.limit) + }), + response: { + 200: z.object({ + certificates: z.array(CertificatesSchema), + totalCount: z.number() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { certificates, totalCount } = await server.services.project.listProjectCertificates({ + filter: { + projectId: req.params.projectId, + type: ProjectFilterType.ID + }, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + ...req.query + }); + return { certificates, totalCount }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/pki-alerts", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.PkiAlerting], + params: z.object({ + projectId: z.string().trim() + }), + response: { + 200: z.object({ + alerts: z.array(PkiAlertsSchema) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { alerts } = await server.services.project.listProjectAlerts({ + projectId: req.params.projectId, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type + }); + + return { alerts }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/pki-collections", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], + params: z.object({ + projectId: z.string().trim() + }), + response: { + 200: z.object({ + collections: z.array(PkiCollectionsSchema) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { pkiCollections } = await server.services.project.listProjectPkiCollections({ + projectId: req.params.projectId, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type + }); + + return { collections: pkiCollections }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/pki-subscribers", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.PkiSubscribers], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_PKI_SUBSCRIBERS.projectId) + }), + response: { + 200: z.object({ + subscribers: z.array(sanitizedPkiSubscriber) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const subscribers = await server.services.project.listProjectPkiSubscribers({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + projectId: req.params.projectId + }); + + return { subscribers }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/certificate-templates", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], + params: z.object({ + projectId: z.string().trim() + }), + response: { + 200: z.object({ + certificateTemplates: sanitizedCertificateTemplate.array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { certificateTemplates } = await server.services.project.listProjectCertificateTemplates({ + projectId: req.params.projectId, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type + }); + + return { certificateTemplates }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/ssh-certificates", + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CAS.projectId) + }), + querystring: z.object({ + offset: z.coerce.number().default(0).describe(PROJECTS.LIST_SSH_CERTIFICATES.offset), + limit: z.coerce.number().default(25).describe(PROJECTS.LIST_SSH_CERTIFICATES.limit) + }), + response: { + 200: z.object({ + certificates: z.array(sanitizedSshCertificate), + totalCount: z.number() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { certificates, totalCount } = await server.services.project.listProjectSshCertificates({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + projectId: req.params.projectId, + offset: req.query.offset, + limit: req.query.limit + }); + + return { certificates, totalCount }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/ssh-certificate-templates", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateTemplates], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CERTIFICATE_TEMPLATES.projectId) + }), + response: { + 200: z.object({ + certificateTemplates: z.array(sanitizedSshCertificateTemplate) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { certificateTemplates } = await server.services.project.listProjectSshCertificateTemplates({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + projectId: req.params.projectId + }); + + return { certificateTemplates }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/ssh-cas", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CAS.projectId) + }), + response: { + 200: z.object({ + cas: z.array(sanitizedSshCa) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const cas = await server.services.project.listProjectSshCas({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + projectId: req.params.projectId + }); + + return { cas }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/ssh-hosts", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SshHosts], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_SSH_HOSTS.projectId) + }), + response: { + 200: z.object({ + hosts: z.array( + sanitizedSshHost.extend({ + loginMappings: loginMappingSchema + .extend({ + source: z.nativeEnum(LoginMappingSource) + }) + .array() + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const hosts = await server.services.project.listProjectSshHosts({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + projectId: req.params.projectId + }); + + return { hosts }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/ssh-host-groups", + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.SshHostGroups], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_SSH_HOST_GROUPS.projectId) + }), + response: { + 200: z.object({ + groups: z.array( + sanitizedSshHostGroup.extend({ + loginMappings: loginMappingSchema.array(), + hostCount: z.number() + }) + ) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const groups = await server.services.project.listProjectSshHostGroups({ + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + actor: req.permission.type, + projectId: req.params.projectId + }); + + return { groups }; + } + }); }; diff --git a/backend/src/server/routes/v1/secret-tag-router.ts b/backend/src/server/routes/v1/secret-tag-router.ts index 01ba783fe..3c6c99eaf 100644 --- a/backend/src/server/routes/v1/secret-tag-router.ts +++ b/backend/src/server/routes/v1/secret-tag-router.ts @@ -22,20 +22,20 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - workspaceTags: SecretTagsSchema.array() + tags: SecretTagsSchema.array() }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaceTags = await server.services.secretTag.getProjectTags({ + const tags = await server.services.secretTag.getProjectTags({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, projectId: req.params.projectId }); - return { workspaceTags }; + return { tags }; } }); @@ -55,20 +55,20 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ // akhilmhdh: for terraform backward compatiability - workspaceTag: SecretTagsSchema.extend({ name: z.string() }) + tag: SecretTagsSchema.extend({ name: z.string() }) }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaceTag = await server.services.secretTag.getTagById({ + const tag = await server.services.secretTag.getTagById({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, id: req.params.tagId }); - return { workspaceTag }; + return { tag }; } }); @@ -88,13 +88,13 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ // akhilmhdh: for terraform backward compatiability - workspaceTag: SecretTagsSchema.extend({ name: z.string() }) + tag: SecretTagsSchema.extend({ name: z.string() }) }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaceTag = await server.services.secretTag.getTagBySlug({ + const tag = await server.services.secretTag.getTagBySlug({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -102,7 +102,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { slug: req.params.tagSlug, projectId: req.params.projectId }); - return { workspaceTag }; + return { tag }; } }); @@ -124,13 +124,13 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - workspaceTag: SecretTagsSchema + tag: SecretTagsSchema }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaceTag = await server.services.secretTag.createTag({ + const tag = await server.services.secretTag.createTag({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -138,7 +138,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { projectId: req.params.projectId, ...req.body }); - return { workspaceTag }; + return { tag }; } }); @@ -161,13 +161,13 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - workspaceTag: SecretTagsSchema + tag: SecretTagsSchema }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaceTag = await server.services.secretTag.updateTag({ + const tag = await server.services.secretTag.updateTag({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, @@ -175,7 +175,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { ...req.body, id: req.params.tagId }); - return { workspaceTag }; + return { tag }; } }); @@ -194,20 +194,20 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - workspaceTag: SecretTagsSchema + tag: SecretTagsSchema }) } }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const workspaceTag = await server.services.secretTag.deleteTag({ + const tag = await server.services.secretTag.deleteTag({ actor: req.permission.type, actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, id: req.params.tagId }); - return { workspaceTag }; + return { tag }; } }); }; diff --git a/backend/src/server/routes/v1/webhook-router.ts b/backend/src/server/routes/v1/webhook-router.ts index 377af135c..386628d28 100644 --- a/backend/src/server/routes/v1/webhook-router.ts +++ b/backend/src/server/routes/v1/webhook-router.ts @@ -39,7 +39,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { body: z .object({ type: z.nativeEnum(WebhookType).default(WebhookType.GENERAL), - workspaceId: z.string().trim(), + projectId: z.string().trim(), environment: z.string().trim(), webhookUrl: z.string().url().trim(), webhookSecretKey: z.string().trim().optional(), @@ -67,13 +67,12 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { actorId: req.permission.id, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - projectId: req.body.workspaceId, ...req.body }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.CREATE_WEBHOOK, metadata: { @@ -216,7 +215,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { onRequest: verifyAuth([AuthMode.JWT]), schema: { querystring: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), environment: z.string().trim().optional(), secretPath: z .string() @@ -238,7 +237,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.query, - projectId: req.query.workspaceId + projectId: req.query.projectId }); return { message: "Successfully fetched webhook", webhooks }; } diff --git a/backend/src/server/routes/v2/deprecated-group-project-router.ts b/backend/src/server/routes/v2/deprecated-group-project-router.ts new file mode 100644 index 000000000..f0e4ee705 --- /dev/null +++ b/backend/src/server/routes/v2/deprecated-group-project-router.ts @@ -0,0 +1,363 @@ +import { z } from "zod"; + +import { + GroupProjectMembershipsSchema, + GroupsSchema, + ProjectMembershipRole, + ProjectUserMembershipRolesSchema, + UsersSchema +} from "@app/db/schemas"; +import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; +import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs"; +import { ms } from "@app/lib/ms"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; +import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types"; + +export const registerDeprecatedGroupProjectRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "POST", + url: "/:projectId/groups/:groupIdOrName", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], + description: "Add group to project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.ADD_GROUP_TO_PROJECT.projectId), + groupIdOrName: z.string().trim().describe(PROJECTS.ADD_GROUP_TO_PROJECT.groupIdOrName) + }), + body: z + .object({ + role: z + .string() + .trim() + .min(1) + .default(ProjectMembershipRole.NoAccess) + .describe(PROJECTS.ADD_GROUP_TO_PROJECT.role), + roles: z + .array( + z.union([ + z.object({ + role: z.string(), + isTemporary: z.literal(false).default(false) + }), + z.object({ + role: z.string(), + isTemporary: z.literal(true), + temporaryMode: z.nativeEnum(ProjectUserMembershipTemporaryMode), + temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"), + temporaryAccessStartTime: z.string().datetime() + }) + ]) + ) + .optional() + }) + .refine((data) => data.role || data.roles, { + message: "Either role or roles must be present", + path: ["role", "roles"] + }), + response: { + 200: z.object({ + groupMembership: GroupProjectMembershipsSchema + }) + } + }, + handler: async (req) => { + const groupMembership = await server.services.groupProject.addGroupToProject({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + roles: req.body.roles || [{ role: req.body.role }], + projectId: req.params.projectId, + groupIdOrName: req.params.groupIdOrName + }); + + return { groupMembership }; + } + }); + + server.route({ + method: "PATCH", + url: "/:projectId/groups/:groupId", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], + description: "Update group in project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.UPDATE_GROUP_IN_PROJECT.projectId), + groupId: z.string().trim().describe(PROJECTS.UPDATE_GROUP_IN_PROJECT.groupId) + }), + body: z.object({ + roles: z + .array( + z.union([ + z.object({ + role: z.string(), + isTemporary: z.literal(false).default(false) + }), + z.object({ + role: z.string(), + isTemporary: z.literal(true), + temporaryMode: z.nativeEnum(ProjectUserMembershipTemporaryMode), + temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"), + temporaryAccessStartTime: z.string().datetime() + }) + ]) + ) + .min(1) + .describe(PROJECTS.UPDATE_GROUP_IN_PROJECT.roles) + }), + response: { + 200: z.object({ + roles: ProjectUserMembershipRolesSchema.array() + }) + } + }, + handler: async (req) => { + const roles = await server.services.groupProject.updateGroupInProject({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + groupId: req.params.groupId, + roles: req.body.roles + }); + + return { roles }; + } + }); + + server.route({ + method: "DELETE", + url: "/:projectId/groups/:groupId", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + config: { + rateLimit: writeLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], + description: "Remove group from project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.REMOVE_GROUP_FROM_PROJECT.projectId), + groupId: z.string().trim().describe(PROJECTS.REMOVE_GROUP_FROM_PROJECT.groupId) + }), + response: { + 200: z.object({ + groupMembership: GroupProjectMembershipsSchema + }) + } + }, + handler: async (req) => { + const groupMembership = await server.services.groupProject.removeGroupFromProject({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + groupId: req.params.groupId, + projectId: req.params.projectId + }); + + return { groupMembership }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/groups", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], + description: "Return list of groups in project", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECTS.LIST_GROUPS_IN_PROJECT.projectId) + }), + response: { + 200: z.object({ + groupMemberships: z + .object({ + id: z.string(), + groupId: z.string(), + createdAt: z.date(), + updatedAt: z.date(), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ), + group: GroupsSchema.pick({ name: true, id: true, slug: true }) + }) + .array() + }) + } + }, + handler: async (req) => { + const groupMemberships = await server.services.groupProject.listGroupsInProject({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId + }); + + return { groupMemberships }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/groups/:groupId", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], + description: "Return project group", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim(), + groupId: z.string().trim() + }), + response: { + 200: z.object({ + groupMembership: z.object({ + id: z.string(), + groupId: z.string(), + createdAt: z.date(), + updatedAt: z.date(), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ), + group: GroupsSchema.pick({ name: true, id: true, slug: true }) + }) + }) + } + }, + handler: async (req) => { + const groupMembership = await server.services.groupProject.getGroupInProject({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.params + }); + + return { groupMembership }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/groups/:groupId/users", + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + config: { + rateLimit: readLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], + description: "Return project group users", + params: z.object({ + projectId: z.string().trim().describe(GROUPS.LIST_USERS.projectId), + groupId: z.string().trim().describe(GROUPS.LIST_USERS.id) + }), + querystring: z.object({ + offset: z.coerce.number().min(0).max(100).default(0).describe(GROUPS.LIST_USERS.offset), + limit: z.coerce.number().min(1).max(100).default(10).describe(GROUPS.LIST_USERS.limit), + username: z.string().trim().optional().describe(GROUPS.LIST_USERS.username), + search: z.string().trim().optional().describe(GROUPS.LIST_USERS.search), + filter: z.nativeEnum(EFilterReturnedUsers).optional().describe(GROUPS.LIST_USERS.filterUsers) + }), + response: { + 200: z.object({ + users: UsersSchema.pick({ + email: true, + username: true, + firstName: true, + lastName: true, + id: true + }) + .merge( + z.object({ + isPartOfGroup: z.boolean(), + joinedGroupAt: z.date().nullable() + }) + ) + .array(), + totalCount: z.number() + }) + } + }, + handler: async (req) => { + const { users, totalCount } = await server.services.groupProject.listProjectGroupUsers({ + id: req.params.groupId, + projectId: req.params.projectId, + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.query + }); + + return { users, totalCount }; + } + }); +}; diff --git a/backend/src/server/routes/v2/deprecated-identity-project-router.ts b/backend/src/server/routes/v2/deprecated-identity-project-router.ts new file mode 100644 index 000000000..c16c874ae --- /dev/null +++ b/backend/src/server/routes/v2/deprecated-identity-project-router.ts @@ -0,0 +1,418 @@ +import { z } from "zod"; + +import { + IdentitiesSchema, + IdentityProjectMembershipsSchema, + ProjectMembershipRole, + ProjectUserMembershipRolesSchema +} from "@app/db/schemas"; +import { ApiDocsTags, ORGANIZATIONS, PROJECT_IDENTITIES } from "@app/lib/api-docs"; +import { BadRequestError } from "@app/lib/errors"; +import { ms } from "@app/lib/ms"; +import { OrderByDirection } from "@app/lib/types"; +import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { AuthMode } from "@app/services/auth/auth-type"; +import { ProjectIdentityOrderBy } from "@app/services/identity-project/identity-project-types"; +import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types"; + +import { SanitizedProjectSchema } from "../sanitizedSchemas"; + +export const registerDeprecatedIdentityProjectRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "POST", + url: "/:projectId/identity-memberships/:identityId", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], + description: "Create project identity membership", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim(), + identityId: z.string().trim() + }), + body: z.object({ + // @depreciated + role: z.string().trim().optional().default(ProjectMembershipRole.NoAccess), + roles: z + .array( + z.union([ + z.object({ + role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role), + isTemporary: z + .literal(false) + .default(false) + .describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role) + }), + z.object({ + role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role), + isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role), + temporaryMode: z + .nativeEnum(ProjectUserMembershipTemporaryMode) + .describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role), + temporaryRange: z + .string() + .refine((val) => ms(val) > 0, "Temporary range must be a positive number") + .describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role), + temporaryAccessStartTime: z + .string() + .datetime() + .describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role) + }) + ]) + ) + .describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.description) + .optional() + }), + response: { + 200: z.object({ + identityMembership: IdentityProjectMembershipsSchema + }) + } + }, + handler: async (req) => { + const { role, roles } = req.body; + if (!role && !roles) throw new BadRequestError({ message: "You must provide either role or roles field" }); + + const identityMembership = await server.services.identityProject.createProjectIdentity({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId, + projectId: req.params.projectId, + roles: roles || [{ role }] + }); + return { identityMembership }; + } + }); + + server.route({ + method: "PATCH", + url: "/:projectId/identity-memberships/:identityId", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], + description: "Update project identity memberships", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.projectId), + identityId: z.string().trim().describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.identityId) + }), + body: z.object({ + roles: z + .array( + z.union([ + z.object({ + role: z.string().describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.role), + isTemporary: z + .literal(false) + .default(false) + .describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.isTemporary) + }), + z.object({ + role: z.string().describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.role), + isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.isTemporary), + temporaryMode: z + .nativeEnum(ProjectUserMembershipTemporaryMode) + .describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.temporaryMode), + temporaryRange: z + .string() + .refine((val) => ms(val) > 0, "Temporary range must be a positive number") + .describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.temporaryRange), + temporaryAccessStartTime: z + .string() + .datetime() + .describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.temporaryAccessStartTime) + }) + ]) + ) + .min(1) + .describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.description) + }), + response: { + 200: z.object({ + roles: ProjectUserMembershipRolesSchema.array() + }) + } + }, + handler: async (req) => { + const roles = await server.services.identityProject.updateProjectIdentity({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId, + projectId: req.params.projectId, + roles: req.body.roles + }); + return { roles }; + } + }); + + server.route({ + method: "DELETE", + url: "/:projectId/identity-memberships/:identityId", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], + description: "Delete project identity memberships", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECT_IDENTITIES.DELETE_IDENTITY_MEMBERSHIP.projectId), + identityId: z.string().trim().describe(PROJECT_IDENTITIES.DELETE_IDENTITY_MEMBERSHIP.identityId) + }), + response: { + 200: z.object({ + identityMembership: IdentityProjectMembershipsSchema + }) + } + }, + handler: async (req) => { + const identityMembership = await server.services.identityProject.deleteProjectIdentity({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityId: req.params.identityId, + projectId: req.params.projectId + }); + return { identityMembership }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/identity-memberships", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], + description: "Return project identity memberships", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECT_IDENTITIES.LIST_IDENTITY_MEMBERSHIPS.projectId) + }), + querystring: z.object({ + offset: z.coerce + .number() + .min(0) + .default(0) + .describe(PROJECT_IDENTITIES.LIST_IDENTITY_MEMBERSHIPS.offset) + .optional(), + limit: z.coerce + .number() + .min(1) + .max(20000) // TODO: temp limit until combobox added to add identity to project modal, reduce once added + .default(100) + .describe(PROJECT_IDENTITIES.LIST_IDENTITY_MEMBERSHIPS.limit) + .optional(), + orderBy: z + .nativeEnum(ProjectIdentityOrderBy) + .default(ProjectIdentityOrderBy.Name) + .describe(ORGANIZATIONS.LIST_IDENTITY_MEMBERSHIPS.orderBy) + .optional(), + orderDirection: z + .nativeEnum(OrderByDirection) + .default(OrderByDirection.ASC) + .describe(ORGANIZATIONS.LIST_IDENTITY_MEMBERSHIPS.orderDirection) + .optional(), + search: z.string().trim().describe(PROJECT_IDENTITIES.LIST_IDENTITY_MEMBERSHIPS.search).optional() + }), + response: { + 200: z.object({ + identityMemberships: z + .object({ + id: z.string(), + identityId: z.string(), + createdAt: z.date(), + updatedAt: z.date(), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ), + identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ + authMethods: z.array(z.string()) + }), + project: SanitizedProjectSchema.pick({ name: true, id: true }) + }) + .array(), + totalCount: z.number() + }) + } + }, + handler: async (req) => { + const { identityMemberships, totalCount } = await server.services.identityProject.listProjectIdentities({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + limit: req.query.limit, + offset: req.query.offset, + orderBy: req.query.orderBy, + orderDirection: req.query.orderDirection, + search: req.query.search + }); + + return { identityMemberships, totalCount }; + } + }); + + server.route({ + method: "GET", + url: "/:projectId/identity-memberships/:identityId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], + description: "Return project identity membership", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + projectId: z.string().trim().describe(PROJECT_IDENTITIES.GET_IDENTITY_MEMBERSHIP_BY_ID.projectId), + identityId: z.string().trim().describe(PROJECT_IDENTITIES.GET_IDENTITY_MEMBERSHIP_BY_ID.identityId) + }), + response: { + 200: z.object({ + identityMembership: z.object({ + id: z.string(), + identityId: z.string(), + createdAt: z.date(), + updatedAt: z.date(), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ), + identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ + authMethods: z.array(z.string()) + }), + project: SanitizedProjectSchema.pick({ name: true, id: true }) + }) + }) + } + }, + handler: async (req) => { + const identityMembership = await server.services.identityProject.getProjectIdentityByIdentityId({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId: req.params.projectId, + identityId: req.params.identityId + }); + return { identityMembership }; + } + }); + + server.route({ + method: "GET", + url: "/identity-memberships/:identityMembershipId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], + params: z.object({ + identityMembershipId: z.string().trim() + }), + response: { + 200: z.object({ + identityMembership: z.object({ + id: z.string(), + identityId: z.string(), + createdAt: z.date(), + updatedAt: z.date(), + roles: z.array( + z.object({ + id: z.string(), + role: z.string(), + customRoleId: z.string().optional().nullable(), + customRoleName: z.string().optional().nullable(), + customRoleSlug: z.string().optional().nullable(), + isTemporary: z.boolean(), + temporaryMode: z.string().optional().nullable(), + temporaryRange: z.string().nullable().optional(), + temporaryAccessStartTime: z.date().nullable().optional(), + temporaryAccessEndTime: z.date().nullable().optional() + }) + ), + identity: IdentitiesSchema.pick({ name: true, id: true }).extend({ + authMethods: z.array(z.string()) + }), + project: SanitizedProjectSchema.pick({ name: true, id: true }) + }) + }) + } + }, + handler: async (req) => { + const identityMembership = await server.services.identityProject.getProjectIdentityByMembershipId({ + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + identityMembershipId: req.params.identityMembershipId + }); + return { identityMembership }; + } + }); +}; diff --git a/backend/src/server/routes/v2/project-membership-router.ts b/backend/src/server/routes/v2/deprecated-project-membership-router.ts similarity index 96% rename from backend/src/server/routes/v2/project-membership-router.ts rename to backend/src/server/routes/v2/deprecated-project-membership-router.ts index 76f1e9c5e..d88d2f996 100644 --- a/backend/src/server/routes/v2/project-membership-router.ts +++ b/backend/src/server/routes/v2/deprecated-project-membership-router.ts @@ -7,7 +7,7 @@ import { writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; -export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => { +export const registerDeprecatedProjectMembershipRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", url: "/:projectId/memberships", @@ -71,7 +71,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider projectId: req.params.projectId, ...req.auditLogInfo, event: { - type: EventType.ADD_BATCH_WORKSPACE_MEMBER, + type: EventType.ADD_BATCH_PROJECT_MEMBER, metadata: memberships.map(({ userId, id }) => ({ userId: userId || "", membershipId: id, @@ -141,7 +141,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider ...req.auditLogInfo, projectId: req.params.projectId, event: { - type: EventType.REMOVE_WORKSPACE_MEMBER, + type: EventType.REMOVE_PROJECT_MEMBER, metadata: { userId: membership.userId, email: "" diff --git a/backend/src/server/routes/v2/project-router.ts b/backend/src/server/routes/v2/deprecated-project-router.ts similarity index 92% rename from backend/src/server/routes/v2/project-router.ts rename to backend/src/server/routes/v2/deprecated-project-router.ts index 8b9091364..7c1045855 100644 --- a/backend/src/server/routes/v2/project-router.ts +++ b/backend/src/server/routes/v2/deprecated-project-router.ts @@ -35,7 +35,8 @@ const projectWithEnv = SanitizedProjectSchema.extend({ kmsSecretManagerKeyId: z.string().nullable().optional() }); -export const registerProjectRouter = async (server: FastifyZodProvider) => { +export const registerDeprecatedProjectRouter = async (server: FastifyZodProvider) => { + // depreciated /* Get project key */ server.route({ method: "GET", @@ -46,7 +47,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { schema: { description: "Return encrypted project key", params: z.object({ - workspaceId: z.string().trim().describe(PROJECTS.GET_KEY.workspaceId) + workspaceId: z.string().trim().describe(PROJECTS.GET_KEY.projectId) }), response: { 200: ProjectKeysSchema.merge( @@ -72,7 +73,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { ...req.auditLogInfo, projectId: req.params.workspaceId, event: { - type: EventType.GET_WORKSPACE_KEY, + type: EventType.GET_PROJECT_KEY, metadata: { keyId: key?.id as string } @@ -83,68 +84,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } }); - /* Start upgrade of a project */ - server.route({ - method: "POST", - url: "/:projectId/upgrade", - config: { - rateLimit: writeLimit - }, - schema: { - params: z.object({ - projectId: z.string().trim() - }), - body: z.object({ - userPrivateKey: z.string().trim() - }), - response: { - 200: z.void() - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - await server.services.project.upgradeProject({ - actorId: req.permission.id, - actorOrgId: req.permission.orgId, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - projectId: req.params.projectId, - userPrivateKey: req.body.userPrivateKey - }); - } - }); - - /* Get upgrade status of project */ - server.route({ - url: "/:projectId/upgrade/status", - method: "GET", - config: { - rateLimit: readLimit - }, - schema: { - params: z.object({ - projectId: z.string().trim() - }), - response: { - 200: z.object({ - status: z.string().nullable() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const status = await server.services.project.getProjectUpgradeStatus({ - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId: req.params.projectId, - actor: req.permission.type, - actorId: req.permission.id - }); - - return { status }; - } - }); - /* Create new project */ server.route({ method: "POST", @@ -186,8 +125,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { actor: req.permission.type, actorOrgId: req.permission.orgId, actorAuthMethod: req.permission.authMethod, - workspaceName: req.body.projectName, - workspaceDescription: req.body.projectDescription, + projectName: req.body.projectName, + projectDescription: req.body.projectDescription, slug: req.body.slug, kmsKeyId: req.body.kmsKeyId, template: req.body.template, @@ -224,6 +163,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { }); /* Delete a project by slug */ + // moved to DELETE /v1/projects/slug/:slug server.route({ method: "DELETE", url: "/:slug", @@ -276,6 +216,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { }); /* Get a project by slug */ + // moved to GET /v1/projects/slug/:slug server.route({ method: "GET", url: "/:slug", @@ -337,7 +278,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { 200: SanitizedProjectSchema } }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { const project = await server.services.project.updateProject({ diff --git a/backend/src/server/routes/v2/index.ts b/backend/src/server/routes/v2/index.ts index 93c422d15..aade29bb7 100644 --- a/backend/src/server/routes/v2/index.ts +++ b/backend/src/server/routes/v2/index.ts @@ -1,13 +1,15 @@ import { registerCaRouter } from "./certificate-authority-router"; -import { registerGroupProjectRouter } from "./group-project-router"; +import { registerDeprecatedGroupProjectRouter } from "./deprecated-group-project-router"; +import { registerDeprecatedIdentityProjectRouter } from "./deprecated-identity-project-router"; +import { registerDeprecatedProjectMembershipRouter } from "./deprecated-project-membership-router"; +import { registerDeprecatedProjectRouter } from "./deprecated-project-router"; import { registerIdentityOrgRouter } from "./identity-org-router"; -import { registerIdentityProjectRouter } from "./identity-project-router"; import { registerMfaRouter } from "./mfa-router"; import { registerOrgRouter } from "./organization-router"; import { registerPasswordRouter } from "./password-router"; import { registerPkiTemplatesRouter } from "./pki-templates-router"; -import { registerProjectMembershipRouter } from "./project-membership-router"; -import { registerProjectRouter } from "./project-router"; +import { registerSecretFolderRouter } from "./secret-folder-router"; +import { registerSecretImportRouter } from "./secret-import-router"; import { registerServiceTokenRouter } from "./service-token-router"; import { registerUserRouter } from "./user-router"; @@ -32,12 +34,17 @@ export const registerV2Routes = async (server: FastifyZodProvider) => { }, { prefix: "/organizations" } ); + + await server.register(registerSecretFolderRouter, { prefix: "/folders" }); + await server.register(registerSecretImportRouter, { prefix: "/secret-imports" }); + + // moved to v1/projects await server.register( async (projectServer) => { - await projectServer.register(registerProjectRouter); - await projectServer.register(registerIdentityProjectRouter); - await projectServer.register(registerGroupProjectRouter); - await projectServer.register(registerProjectMembershipRouter); + await projectServer.register(registerDeprecatedProjectRouter); + await projectServer.register(registerDeprecatedIdentityProjectRouter); + await projectServer.register(registerDeprecatedGroupProjectRouter); + await projectServer.register(registerDeprecatedProjectMembershipRouter); }, { prefix: "/workspace" } ); diff --git a/backend/src/server/routes/v1/secret-folder-router.ts b/backend/src/server/routes/v2/secret-folder-router.ts similarity index 80% rename from backend/src/server/routes/v1/secret-folder-router.ts rename to backend/src/server/routes/v2/secret-folder-router.ts index 871259147..0bf062452 100644 --- a/backend/src/server/routes/v1/secret-folder-router.ts +++ b/backend/src/server/routes/v2/secret-folder-router.ts @@ -28,7 +28,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } ], body: z.object({ - workspaceId: z.string().trim().describe(FOLDERS.CREATE.workspaceId), + projectId: z.string().trim().describe(FOLDERS.CREATE.projectId), environment: z.string().trim().describe(FOLDERS.CREATE.environment), name: z .string() @@ -43,17 +43,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => .default("/") .transform(prefixWithSlash) // Transformations get skipped if path is undefined .transform(removeTrailingSlash) - .describe(FOLDERS.CREATE.path) - .optional(), - // backward compatibility with cli - directory: z - .string() - .trim() - .default("/") - .transform(prefixWithSlash) // Transformations get skipped if directory is undefined - .transform(removeTrailingSlash) - .describe(FOLDERS.CREATE.directory) - .optional(), + .describe(FOLDERS.CREATE.path), description: z.string().optional().nullable().describe(FOLDERS.CREATE.description) }), response: { @@ -66,27 +56,24 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const path = req.body.path || req.body.directory || "/"; const folder = await server.services.folder.createFolder({ actorId: req.permission.id, actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.body, - projectId: req.body.workspaceId, - path, description: req.body.description }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.CREATE_FOLDER, metadata: { environment: req.body.environment, folderId: folder.id, folderName: folder.name, - folderPath: path, + folderPath: req.body.path, ...(req.body.description ? { description: req.body.description } : {}) } } @@ -115,7 +102,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => folderId: z.string().describe(FOLDERS.UPDATE.folderId) }), body: z.object({ - workspaceId: z.string().trim().describe(FOLDERS.UPDATE.workspaceId), + projectId: z.string().trim().describe(FOLDERS.UPDATE.projectId), environment: z.string().trim().describe(FOLDERS.UPDATE.environment), name: z .string() @@ -130,17 +117,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => .default("/") .transform(prefixWithSlash) // Transformations get skipped if path is undefined .transform(removeTrailingSlash) - .describe(FOLDERS.UPDATE.path) - .optional(), - // backward compatibility with cli - directory: z - .string() - .trim() - .default("/") - .transform(prefixWithSlash) // Transformations get skipped if directory is undefined - .transform(removeTrailingSlash) - .describe(FOLDERS.UPDATE.directory) - .optional(), + .describe(FOLDERS.UPDATE.path), description: z.string().optional().nullable().describe(FOLDERS.UPDATE.description) }), response: { @@ -153,26 +130,23 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const path = req.body.path || req.body.directory || "/"; const { folder, old } = await server.services.folder.updateFolder({ actorId: req.permission.id, actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.body, - projectId: req.body.workspaceId, - id: req.params.folderId, - path + id: req.params.folderId }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.UPDATE_FOLDER, metadata: { environment: req.body.environment, folderId: folder.id, - folderPath: path, + folderPath: req.body.path, newFolderName: folder.name, oldFolderName: old.name } @@ -198,7 +172,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } ], body: z.object({ - projectSlug: z.string().trim().describe(FOLDERS.UPDATE.projectSlug), + projectId: z.string().trim().describe(FOLDERS.UPDATE.projectId), folders: z .object({ id: z.string().describe(FOLDERS.UPDATE.folderId), @@ -281,7 +255,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => folderIdOrName: z.string().describe(FOLDERS.DELETE.folderIdOrName) }), body: z.object({ - workspaceId: z.string().trim().describe(FOLDERS.DELETE.workspaceId), + projectId: z.string().trim().describe(FOLDERS.DELETE.projectId), environment: z.string().trim().describe(FOLDERS.DELETE.environment), path: z .string() @@ -290,16 +264,6 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => .transform(prefixWithSlash) // Transformations get skipped if path is undefined .transform(removeTrailingSlash) .describe(FOLDERS.DELETE.path) - .optional(), - // keep this here as cli need directory - directory: z - .string() - .trim() - .default("/") - .transform(prefixWithSlash) // Transformations get skipped if directory is undefined - .transform(removeTrailingSlash) - .describe(FOLDERS.DELETE.directory) - .optional() }), response: { 200: z.object({ @@ -309,26 +273,23 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const path = req.body.path || req.body.directory || "/"; const folder = await server.services.folder.deleteFolder({ actorId: req.permission.id, actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.body, - projectId: req.body.workspaceId, - idOrName: req.params.folderIdOrName, - path + idOrName: req.params.folderIdOrName }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.DELETE_FOLDER, metadata: { environment: req.body.environment, folderId: folder.id, - folderPath: path, + folderPath: req.body.path, folderName: folder.name } } @@ -353,7 +314,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } ], querystring: z.object({ - workspaceId: z.string().trim().describe(FOLDERS.LIST.workspaceId), + projectId: z.string().trim().describe(FOLDERS.LIST.projectId), environment: z.string().trim().describe(FOLDERS.LIST.environment), lastSecretModified: z.string().datetime().trim().optional().describe(FOLDERS.LIST.lastSecretModified), path: z @@ -361,16 +322,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => .trim() .transform(prefixWithSlash) // Transformations get skipped if path is undefined .transform(removeTrailingSlash) - .describe(FOLDERS.LIST.path) - .optional(), - // backward compatibility with cli - directory: z - .string() - .trim() - .transform(prefixWithSlash) // Transformations get skipped if directory is undefined - .transform(removeTrailingSlash) - .describe(FOLDERS.LIST.directory) - .optional(), + .describe(FOLDERS.LIST.path), recursive: booleanSchema.default(false).describe(FOLDERS.LIST.recursive) }), response: { @@ -383,15 +335,12 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { - const path = req.query.path || req.query.directory || "/"; const folders = await server.services.folder.getFolders({ actorId: req.permission.id, actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - ...req.query, - projectId: req.query.workspaceId, - path + ...req.query }); return { folders }; } diff --git a/backend/src/server/routes/v1/secret-import-router.ts b/backend/src/server/routes/v2/secret-import-router.ts similarity index 85% rename from backend/src/server/routes/v1/secret-import-router.ts rename to backend/src/server/routes/v2/secret-import-router.ts index fca11f8a0..d9802c4b3 100644 --- a/backend/src/server/routes/v1/secret-import-router.ts +++ b/backend/src/server/routes/v2/secret-import-router.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { SecretImportsSchema, SecretsSchema } from "@app/db/schemas"; +import { SecretImportsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { ApiDocsTags, SECRET_IMPORTS } from "@app/lib/api-docs"; import { removeTrailingSlash } from "@app/lib/fn"; @@ -27,7 +27,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => } ], body: z.object({ - workspaceId: z.string().trim().describe(SECRET_IMPORTS.CREATE.workspaceId), + projectId: z.string().trim().describe(SECRET_IMPORTS.CREATE.projectId), environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.environment), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.path), import: z.object({ @@ -55,13 +55,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.body, - projectId: req.body.workspaceId, + projectId: req.body.projectId, data: req.body.import }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.CREATE_SECRET_IMPORT, metadata: { @@ -97,7 +97,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => secretImportId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.secretImportId) }), body: z.object({ - workspaceId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.workspaceId), + projectId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.projectId), environment: z.string().trim().describe(SECRET_IMPORTS.UPDATE.environment), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.UPDATE.path), import: z.object({ @@ -131,13 +131,13 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => actorOrgId: req.permission.orgId, id: req.params.secretImportId, ...req.body, - projectId: req.body.workspaceId, + projectId: req.body.projectId, data: req.body.import }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.UPDATE_SECRET_IMPORT, metadata: { @@ -173,7 +173,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => secretImportId: z.string().trim().describe(SECRET_IMPORTS.DELETE.secretImportId) }), body: z.object({ - workspaceId: z.string().trim().describe(SECRET_IMPORTS.DELETE.workspaceId), + projectId: z.string().trim().describe(SECRET_IMPORTS.DELETE.projectId), environment: z.string().trim().describe(SECRET_IMPORTS.DELETE.environment), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.DELETE.path) }), @@ -197,12 +197,12 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => actorOrgId: req.permission.orgId, id: req.params.secretImportId, ...req.body, - projectId: req.body.workspaceId + projectId: req.body.projectId }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.body.workspaceId, + projectId: req.body.projectId, event: { type: EventType.DELETE_SECRET_IMPORT, metadata: { @@ -236,7 +236,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => secretImportId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.secretImportId) }), body: z.object({ - workspaceId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.workspaceId), + projectId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.projectId), environment: z.string().trim().describe(SECRET_IMPORTS.UPDATE.environment), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.UPDATE.path) }), @@ -255,7 +255,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => actorOrgId: req.permission.orgId, id: req.params.secretImportId, ...req.body, - projectId: req.body.workspaceId + projectId: req.body.projectId }); return { message }; @@ -278,7 +278,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => } ], querystring: z.object({ - workspaceId: z.string().trim().describe(SECRET_IMPORTS.LIST.workspaceId), + projectId: z.string().trim().describe(SECRET_IMPORTS.LIST.projectId), environment: z.string().trim().describe(SECRET_IMPORTS.LIST.environment), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.LIST.path) }), @@ -301,12 +301,12 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, ...req.query, - projectId: req.query.workspaceId + projectId: req.query.projectId }); await server.services.auditLog.createAuditLog({ ...req.auditLogInfo, - projectId: req.query.workspaceId, + projectId: req.query.projectId, event: { type: EventType.GET_SECRET_IMPORTS, metadata: { @@ -386,55 +386,11 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => config: { rateLimit: secretsLimit }, - schema: { - querystring: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash) - }), - response: { - 200: z.object({ - secrets: z - .object({ - secretPath: z.string(), - environment: z.string(), - environmentInfo: z.object({ - id: z.string(), - name: z.string(), - slug: z.string() - }), - folderId: z.string().optional(), - secrets: SecretsSchema.omit({ secretBlindIndex: true }).array() - }) - .array() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), - handler: async (req) => { - const importedSecrets = await server.services.secretImport.getSecretsFromImports({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - ...req.query, - projectId: req.query.workspaceId - }); - return { secrets: importedSecrets }; - } - }); - - server.route({ - url: "/secrets/raw", - method: "GET", - config: { - rateLimit: secretsLimit - }, schema: { hide: false, tags: [ApiDocsTags.SecretImports], querystring: z.object({ - workspaceId: z.string().trim(), + projectId: z.string().trim(), environment: z.string().trim(), path: z.string().trim().default("/").transform(removeTrailingSlash) }), @@ -463,8 +419,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => actor: req.permission.type, actorAuthMethod: req.permission.authMethod, actorOrgId: req.permission.orgId, - ...req.query, - projectId: req.query.workspaceId + ...req.query }); return { secrets: importedSecrets }; } diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/deprecated-secret-router.ts similarity index 96% rename from backend/src/server/routes/v3/secret-router.ts rename to backend/src/server/routes/v3/deprecated-secret-router.ts index ce0d4f188..c037a3dee 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/deprecated-secret-router.ts @@ -39,7 +39,7 @@ const SecretReferenceNodeTree: z.ZodType = SecretReference children: z.lazy(() => SecretReferenceNodeTree.array()) }); -export const registerSecretRouter = async (server: FastifyZodProvider) => { +export const registerDeprecatedSecretRouter = async (server: FastifyZodProvider) => { server.route({ method: "POST", url: "/tags/:secretName", @@ -230,7 +230,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } }) .describe(RAW_SECRETS.LIST.metadataFilter), - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.LIST.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.LIST.projectId), workspaceSlug: z.string().trim().optional().describe(RAW_SECRETS.LIST.workspaceSlug), environment: z.string().trim().optional().describe(RAW_SECRETS.LIST.environment), secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.LIST.secretPath), @@ -298,7 +298,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { workspaceId = projectId; } - if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" }); + if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing project id or environment" }); const { secrets, imports } = await server.services.secret.getSecretsRaw({ actorId: req.permission.id, @@ -336,7 +336,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId, + projectId: workspaceId, environment, secretPath: req.query.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -405,7 +405,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { secretName: z.string().trim().describe(RAW_SECRETS.GET.secretName) }), querystring: z.object({ - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.GET.projectId), workspaceSlug: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceSlug), environment: z.string().trim().optional().describe(RAW_SECRETS.GET.environment), secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath), @@ -495,7 +495,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { distinctId: getTelemetryDistinctId(req), properties: { numberOfSecrets: 1, - workspaceId: secret.workspace, + projectId: secret.workspace, environment, secretPath: req.query.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -526,7 +526,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { secretName: SecretNameSchema.describe(RAW_SECRETS.CREATE.secretName) }), body: z.object({ - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.CREATE.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.CREATE.projectId), projectSlug: z.string().trim().optional().describe(RAW_SECRETS.CREATE.projectSlug), environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment), secretPath: z @@ -638,7 +638,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: projectId, + projectId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -669,7 +669,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { secretName: BaseSecretNameSchema.describe(RAW_SECRETS.UPDATE.secretName) }), body: z.object({ - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.projectId), projectSlug: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.projectSlug), environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment), secretValue: z @@ -791,7 +791,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: projectId, + projectId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -821,7 +821,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { secretName: z.string().min(1).describe(RAW_SECRETS.DELETE.secretName) }), body: z.object({ - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.DELETE.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.DELETE.projectId), projectSlug: z.string().trim().optional().describe(RAW_SECRETS.DELETE.projectSlug), environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment), secretPath: z @@ -909,7 +909,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: projectId, + projectId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1017,7 +1017,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: req.query.workspaceId, + projectId: req.query.workspaceId, environment: req.query.environment, secretPath: req.query.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1097,7 +1097,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: req.query.workspaceId, + projectId: req.query.workspaceId, environment: req.query.environment, secretPath: req.query.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1272,7 +1272,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: req.body.workspaceId, + projectId: req.body.workspaceId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1466,7 +1466,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: req.body.workspaceId, + projectId: req.body.workspaceId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1594,7 +1594,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: 1, - workspaceId: req.body.workspaceId, + projectId: req.body.workspaceId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1781,7 +1781,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: req.body.workspaceId, + projectId: req.body.workspaceId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -1914,7 +1914,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: req.body.workspaceId, + projectId: req.body.workspaceId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -2039,7 +2039,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: req.body.workspaceId, + projectId: req.body.workspaceId, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -2067,7 +2067,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { ], body: z.object({ projectSlug: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.projectSlug), - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.projectId), environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment), secretPath: z .string() @@ -2166,7 +2166,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: secrets[0].workspace, + projectId: secrets[0].workspace, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -2194,7 +2194,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { ], body: z.object({ projectSlug: z.string().trim().optional().describe(RAW_SECRETS.DELETE.projectSlug), - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.DELETE.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.DELETE.projectId), environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment), secretPath: z .string() @@ -2341,7 +2341,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: secrets[0].workspace, + projectId: secrets[0].workspace, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -2369,7 +2369,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { ], body: z.object({ projectSlug: z.string().trim().optional().describe(RAW_SECRETS.DELETE.projectSlug), - workspaceId: z.string().trim().optional().describe(RAW_SECRETS.DELETE.workspaceId), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.DELETE.projectId), environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment), secretPath: z .string() @@ -2459,7 +2459,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { organizationId: req.permission.orgId, properties: { numberOfSecrets: secrets.length, - workspaceId: secrets[0].workspace, + projectId: secrets[0].workspace, environment: req.body.environment, secretPath: req.body.secretPath, channel: getUserAgentType(req.headers["user-agent"]), @@ -2469,95 +2469,4 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { return { secrets }; } }); - - server.route({ - method: "GET", - url: "/raw/:secretName/secret-reference-tree", - config: { - rateLimit: secretsLimit - }, - schema: { - hide: false, - tags: [ApiDocsTags.Secrets], - description: "Get secret reference tree", - security: [ - { - bearerAuth: [] - } - ], - params: z.object({ - secretName: z.string().trim().describe(RAW_SECRETS.GET_REFERENCE_TREE.secretName) - }), - querystring: z.object({ - workspaceId: z.string().trim().describe(RAW_SECRETS.GET_REFERENCE_TREE.workspaceId), - environment: z.string().trim().describe(RAW_SECRETS.GET_REFERENCE_TREE.environment), - secretPath: z - .string() - .trim() - .default("/") - .transform(removeTrailingSlash) - .describe(RAW_SECRETS.GET_REFERENCE_TREE.secretPath) - }), - response: { - 200: z.object({ - tree: SecretReferenceNodeTree, - value: z.string().optional() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const { secretName } = req.params; - const { secretPath, environment, workspaceId } = req.query; - const { tree, value } = await server.services.secret.getSecretReferenceTree({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId: workspaceId, - secretName, - secretPath, - environment - }); - - return { tree, value }; - } - }); - - server.route({ - method: "POST", - url: "/backfill-secret-references", - config: { - rateLimit: secretsLimit - }, - schema: { - description: "Backfill secret references", - security: [ - { - bearerAuth: [] - } - ], - body: z.object({ - projectId: z.string().trim().min(1) - }), - response: { - 200: z.object({ - message: z.string() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const { projectId } = req.body; - const message = await server.services.secret.backfillSecretReferences({ - actorId: req.permission.id, - actor: req.permission.type, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - projectId - }); - - return message; - } - }); }; diff --git a/backend/src/server/routes/v3/index.ts b/backend/src/server/routes/v3/index.ts index 1c31741a1..d7fa94d6b 100644 --- a/backend/src/server/routes/v3/index.ts +++ b/backend/src/server/routes/v3/index.ts @@ -1,7 +1,6 @@ +import { registerDeprecatedSecretRouter } from "./deprecated-secret-router"; import { registerExternalMigrationRouter } from "./external-migration-router"; import { registerLoginRouter } from "./login-router"; -import { registerSecretBlindIndexRouter } from "./secret-blind-index-router"; -import { registerSecretRouter } from "./secret-router"; import { registerSignupRouter } from "./signup-router"; import { registerUserRouter } from "./user-router"; @@ -9,7 +8,6 @@ export const registerV3Routes = async (server: FastifyZodProvider) => { await server.register(registerSignupRouter, { prefix: "/signup" }); await server.register(registerLoginRouter, { prefix: "/auth" }); await server.register(registerUserRouter, { prefix: "/users" }); - await server.register(registerSecretRouter, { prefix: "/secrets" }); - await server.register(registerSecretBlindIndexRouter, { prefix: "/workspaces" }); + await server.register(registerDeprecatedSecretRouter, { prefix: "/secrets" }); await server.register(registerExternalMigrationRouter, { prefix: "/external-migration" }); }; diff --git a/backend/src/server/routes/v3/secret-blind-index-router.ts b/backend/src/server/routes/v3/secret-blind-index-router.ts deleted file mode 100644 index cfb27a58e..000000000 --- a/backend/src/server/routes/v3/secret-blind-index-router.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { z } from "zod"; - -import { SecretsSchema } from "@app/db/schemas"; -import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; -import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; -import { AuthMode } from "@app/services/auth/auth-type"; - -export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider) => { - server.route({ - method: "GET", - url: "/:projectId/secrets/blind-index-status", - config: { - rateLimit: readLimit - }, - schema: { - params: z.object({ - projectId: z.string().trim() - }), - response: { - 200: z.boolean() - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const count = await server.services.secretBlindIndex.getSecretBlindIndexStatus({ - projectId: req.params.projectId, - actorAuthMethod: req.permission.authMethod, - actorId: req.permission.id, - actor: req.permission.type, - actorOrgId: req.permission.orgId - }); - return count === 0; - } - }); - - server.route({ - method: "GET", - url: "/:projectId/secrets", - config: { - rateLimit: readLimit - }, - schema: { - params: z.object({ - projectId: z.string().trim() - }), - response: { - 200: z.object({ - secrets: SecretsSchema.omit({ secretBlindIndex: true }) - .merge( - z.object({ - environment: z.string(), - workspace: z.string() - }) - ) - .array() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - const secrets = await server.services.secretBlindIndex.getProjectSecrets({ - projectId: req.params.projectId, - actorAuthMethod: req.permission.authMethod, - actorId: req.permission.id, - actor: req.permission.type, - actorOrgId: req.permission.orgId - }); - return { secrets }; - } - }); - - server.route({ - method: "POST", - url: "/:projectId/secrets/names", - config: { - rateLimit: writeLimit - }, - schema: { - params: z.object({ - projectId: z.string().trim() - }), - body: z.object({ - secretsToUpdate: z - .object({ - secretName: z.string().trim(), - secretId: z.string().trim() - }) - .array() - }), - response: { - 200: z.object({ - message: z.string() - }) - } - }, - onRequest: verifyAuth([AuthMode.JWT]), - handler: async (req) => { - await server.services.secretBlindIndex.updateProjectSecretName({ - projectId: req.params.projectId, - secretsToUpdate: req.body.secretsToUpdate, - actorAuthMethod: req.permission.authMethod, - actorId: req.permission.id, - actor: req.permission.type, - actorOrgId: req.permission.orgId - }); - return { message: "Successfully named workspace secrets" }; - } - }); -}; diff --git a/backend/src/server/routes/v4/index.ts b/backend/src/server/routes/v4/index.ts new file mode 100644 index 000000000..db2e69222 --- /dev/null +++ b/backend/src/server/routes/v4/index.ts @@ -0,0 +1,5 @@ +import { registerSecretRouter } from "./secret-router"; + +export const registerV4Routes = async (server: FastifyZodProvider) => { + await server.register(registerSecretRouter, { prefix: "/secrets" }); +}; diff --git a/backend/src/server/routes/v4/secret-router.ts b/backend/src/server/routes/v4/secret-router.ts new file mode 100644 index 000000000..ead96668c --- /dev/null +++ b/backend/src/server/routes/v4/secret-router.ts @@ -0,0 +1,1316 @@ +import picomatch from "picomatch"; +import { z } from "zod"; + +import { SecretApprovalRequestsSchema, SecretType, ServiceTokenScopes } from "@app/db/schemas"; +import { EventType, SecretApprovalEvent, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags, RAW_SECRETS } from "@app/lib/api-docs"; +import { BadRequestError } from "@app/lib/errors"; +import { removeTrailingSlash } from "@app/lib/fn"; +import { secretsLimit } from "@app/server/config/rateLimiter"; +import { BaseSecretNameSchema, SecretNameSchema } from "@app/server/lib/schemas"; +import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; +import { getUserAgentType } from "@app/server/plugins/audit-log"; +import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; +import { ActorType, AuthMode } from "@app/services/auth/auth-type"; +import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema"; +import { SecretProtectionType } from "@app/services/secret/secret-types"; +import { SecretUpdateMode } from "@app/services/secret-v2-bridge/secret-v2-bridge-types"; +import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; + +import { SanitizedTagSchema, secretRawSchema } from "../sanitizedSchemas"; + +const SecretReferenceNode = z.object({ + key: z.string(), + value: z.string().optional(), + environment: z.string(), + secretPath: z.string() +}); + +const convertStringBoolean = (defaultValue: boolean = false) => { + return z + .enum(["true", "false"]) + .default(defaultValue ? "true" : "false") + .transform((value) => value === "true"); +}; + +type TSecretReferenceNode = z.infer & { children: TSecretReferenceNode[] }; + +const SecretReferenceNodeTree: z.ZodType = SecretReferenceNode.extend({ + children: z.lazy(() => SecretReferenceNodeTree.array()) +}); + +export const registerSecretRouter = async (server: FastifyZodProvider) => { + server.route({ + method: "GET", + url: "/", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "List secrets", + security: [ + { + bearerAuth: [] + } + ], + querystring: z.object({ + metadataFilter: z + .string() + .optional() + .transform((val) => { + if (!val) return undefined; + + const result: { key?: string; value?: string }[] = []; + const pairs = val.split("|"); + + for (const pair of pairs) { + const keyValuePair: { key?: string; value?: string } = {}; + const parts = pair.split(/[,=]/); + + for (let i = 0; i < parts.length; i += 2) { + const identifier = parts[i].trim().toLowerCase(); + const value = parts[i + 1]?.trim(); + + if (identifier === "key" && value) { + keyValuePair.key = value; + } else if (identifier === "value" && value) { + keyValuePair.value = value; + } + } + + if (keyValuePair.key && keyValuePair.value) { + result.push(keyValuePair); + } + } + + return result.length ? result : undefined; + }) + .superRefine((metadata, ctx) => { + if (metadata && !Array.isArray(metadata)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: + "Invalid secretMetadata format. Correct format is key=value1,value=value2|key=value3,value=value4." + }); + } + + if (metadata) { + if (metadata.length > 10) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "You can only filter by up to 10 metadata fields" + }); + } + + for (const item of metadata) { + if (!item.key && !item.value) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: + "Invalid secretMetadata format, key or value must be provided. Correct format is key=value1,value=value2|key=value3,value=value4." + }); + } + } + } + }) + .describe(RAW_SECRETS.LIST.metadataFilter), + projectId: z.string().trim().optional().describe(RAW_SECRETS.LIST.projectId), + environment: z.string().trim().optional().describe(RAW_SECRETS.LIST.environment), + secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.LIST.secretPath), + viewSecretValue: convertStringBoolean(true).describe(RAW_SECRETS.LIST.viewSecretValue), + expandSecretReferences: convertStringBoolean().describe(RAW_SECRETS.LIST.expand), + recursive: convertStringBoolean().describe(RAW_SECRETS.LIST.recursive), + include_imports: convertStringBoolean().describe(RAW_SECRETS.LIST.includeImports), + tagSlugs: z + .string() + .describe(RAW_SECRETS.LIST.tagSlugs) + .optional() + // split by comma and trim the strings + .transform((el) => (el ? el.split(",").map((i) => i.trim()) : [])) + }), + response: { + 200: z.object({ + secrets: secretRawSchema + .extend({ + secretPath: z.string().optional(), + secretValueHidden: z.boolean(), + secretMetadata: ResourceMetadataSchema.optional(), + tags: SanitizedTagSchema.array().optional() + }) + .array(), + imports: z + .object({ + secretPath: z.string(), + environment: z.string(), + folderId: z.string().optional(), + secrets: secretRawSchema + .omit({ createdAt: true, updatedAt: true }) + .extend({ + secretValueHidden: z.boolean(), + secretMetadata: ResourceMetadataSchema.optional() + }) + .array() + }) + .array() + .optional() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + // just for delivery hero usecase + let { secretPath, environment, projectId } = req.query; + if (req.auth.actor === ActorType.SERVICE) { + const scope = ServiceTokenScopes.parse(req.auth.serviceToken.scopes); + const isSingleScope = scope.length === 1; + if (isSingleScope && !picomatch.scan(scope[0].secretPath).isGlob) { + secretPath = scope[0].secretPath; + environment = scope[0].environment; + projectId = req.auth.serviceToken.projectId; + } + } + + if (!projectId || !environment) throw new BadRequestError({ message: "Missing project id or environment" }); + + const { secrets, imports } = await server.services.secret.getSecretsRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + environment, + expandSecretReferences: req.query.expandSecretReferences, + actorAuthMethod: req.permission.authMethod, + projectId, + viewSecretValue: req.query.viewSecretValue, + path: secretPath, + metadataFilter: req.query.metadataFilter, + includeImports: req.query.include_imports, + recursive: req.query.recursive, + tagSlugs: req.query.tagSlugs + }); + + await server.services.auditLog.createAuditLog({ + projectId, + ...req.auditLogInfo, + event: { + type: EventType.GET_SECRETS, + metadata: { + environment, + secretPath: req.query.secretPath, + numberOfSecrets: secrets.length + } + } + }); + + if (getUserAgentType(req.headers["user-agent"]) !== UserAgentType.K8_OPERATOR) { + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretPulled, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: secrets.length, + projectId, + environment, + secretPath: req.query.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + } + + return { secrets, imports }; + } + }); + + server.route({ + method: "GET", + url: "/id/:secretId", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + params: z.object({ + secretId: z.string() + }), + response: { + 200: z.object({ + secret: secretRawSchema.extend({ + secretPath: z.string(), + tags: SanitizedTagSchema.array().optional(), + secretMetadata: ResourceMetadataSchema.optional() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { secretId } = req.params; + const secret = await server.services.secret.getSecretByIdRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + secretId + }); + + return { secret }; + } + }); + + server.route({ + method: "GET", + url: "/:secretName", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Get a secret by name", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: z.string().trim().describe(RAW_SECRETS.GET.secretName) + }), + querystring: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.GET.projectId), + environment: z.string().trim().optional().describe(RAW_SECRETS.GET.environment), + secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath), + version: z.coerce.number().optional().describe(RAW_SECRETS.GET.version), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.GET.type), + viewSecretValue: convertStringBoolean(true).describe(RAW_SECRETS.GET.viewSecretValue), + expandSecretReferences: convertStringBoolean().describe(RAW_SECRETS.GET.expand), + include_imports: convertStringBoolean().describe(RAW_SECRETS.GET.includeImports) + }), + response: { + 200: z.object({ + secret: secretRawSchema.extend({ + secretValueHidden: z.boolean(), + secretPath: z.string(), + tags: SanitizedTagSchema.array().optional(), + secretMetadata: ResourceMetadataSchema.optional() + }) + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + let { secretPath, environment, projectId } = req.query; + if (req.auth.actor === ActorType.SERVICE) { + const scope = ServiceTokenScopes.parse(req.auth.serviceToken.scopes); + const isSingleScope = scope.length === 1; + if (isSingleScope && !picomatch.scan(scope[0].secretPath).isGlob) { + secretPath = scope[0].secretPath; + environment = scope[0].environment; + projectId = req.auth.serviceToken.projectId; + } + } + + if (!environment) throw new BadRequestError({ message: "Missing environment" }); + if (!projectId) { + throw new BadRequestError({ message: "You must provide workspaceId" }); + } + + const secret = await server.services.secret.getSecretByNameRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + expandSecretReferences: req.query.expandSecretReferences, + environment, + projectId, + viewSecretValue: req.query.viewSecretValue, + path: secretPath, + secretName: req.params.secretName, + type: req.query.type, + includeImports: req.query.include_imports, + version: req.query.version + }); + + await server.services.auditLog.createAuditLog({ + projectId, + ...req.auditLogInfo, + event: { + type: EventType.GET_SECRET, + metadata: { + environment, + secretPath: req.query.secretPath, + secretId: secret.id, + secretKey: req.params.secretName, + secretVersion: secret.version, + secretMetadata: secret.secretMetadata + } + } + }); + + if (getUserAgentType(req.headers["user-agent"]) !== UserAgentType.K8_OPERATOR) { + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretPulled, + organizationId: req.permission.orgId, + distinctId: getTelemetryDistinctId(req), + properties: { + numberOfSecrets: 1, + projectId, + environment, + secretPath: req.query.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + } + return { secret }; + } + }); + + server.route({ + method: "POST", + url: "/:secretName", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Create secret", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: SecretNameSchema.describe(RAW_SECRETS.CREATE.secretName) + }), + body: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.CREATE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.CREATE.secretPath), + secretValue: z + .string() + .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) + .describe(RAW_SECRETS.CREATE.secretValue), + secretComment: z.string().trim().optional().default("").describe(RAW_SECRETS.CREATE.secretComment), + secretMetadata: ResourceMetadataSchema.optional(), + tagIds: z.string().array().optional().describe(RAW_SECRETS.CREATE.tagIds), + skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.CREATE.skipMultilineEncoding), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.CREATE.type), + secretReminderRepeatDays: z + .number() + .optional() + .nullable() + .describe(RAW_SECRETS.CREATE.secretReminderRepeatDays), + secretReminderNote: z + .string() + .max(1024, "Secret reminder note cannot exceed 1024 characters") + .optional() + .nullable() + .describe(RAW_SECRETS.CREATE.secretReminderNote) + }), + response: { + 200: z.union([ + z.object({ + secret: secretRawSchema + }), + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretOperation = await server.services.secret.createSecretRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + environment: req.body.environment, + actorAuthMethod: req.permission.authMethod, + projectId: req.body.projectId, + secretPath: req.body.secretPath, + secretName: req.params.secretName, + type: req.body.type, + secretValue: req.body.secretValue, + skipMultilineEncoding: req.body.skipMultilineEncoding, + secretComment: req.body.secretComment, + secretMetadata: req.body.secretMetadata, + tagIds: req.body.tagIds, + secretReminderNote: req.body.secretReminderNote, + secretReminderRepeatDays: req.body.secretReminderRepeatDays + }); + if (secretOperation.type === SecretProtectionType.Approval) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: secretOperation.approval.committerUserId, + secretApprovalRequestId: secretOperation.approval.id, + secretApprovalRequestSlug: secretOperation.approval.slug, + secretPath: req.body.secretPath, + environment: req.body.environment, + secretKey: req.params.secretName, + eventType: SecretApprovalEvent.Create + } + } + }); + + return { approval: secretOperation.approval }; + } + + const { secret } = secretOperation; + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.CREATE_SECRET, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secretId: secret.id, + secretKey: req.params.secretName, + secretVersion: secret.version, + secretMetadata: req.body.secretMetadata + } + } + }); + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretCreated, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: 1, + projectId: req.body.projectId, + environment: req.body.environment, + secretPath: req.body.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + + return { secret }; + } + }); + + server.route({ + method: "PATCH", + url: "/:secretName", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Update secret", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: BaseSecretNameSchema.describe(RAW_SECRETS.UPDATE.secretName) + }), + body: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.UPDATE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment), + secretValue: z + .string() + .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) + .optional() + .describe(RAW_SECRETS.UPDATE.secretValue), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.UPDATE.secretPath), + skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.UPDATE.skipMultilineEncoding), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.UPDATE.type), + tagIds: z.string().array().optional().describe(RAW_SECRETS.UPDATE.tagIds), + metadata: z.record(z.string()).optional(), + secretMetadata: ResourceMetadataSchema.optional(), + secretReminderNote: z + .string() + .max(1024, "Secret reminder note cannot exceed 1024 characters") + .optional() + .nullable() + .describe(RAW_SECRETS.UPDATE.secretReminderNote), + secretReminderRepeatDays: z + .number() + .optional() + .nullable() + .describe(RAW_SECRETS.UPDATE.secretReminderRepeatDays), + secretReminderRecipients: z.string().array().optional().describe(RAW_SECRETS.UPDATE.secretReminderRecipients), + newSecretName: SecretNameSchema.optional().describe(RAW_SECRETS.UPDATE.newSecretName), + secretComment: z.string().optional().describe(RAW_SECRETS.UPDATE.secretComment) + }), + response: { + 200: z.union([ + z.object({ + secret: secretRawSchema.extend({ + secretValueHidden: z.boolean() + }) + }), + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretOperation = await server.services.secret.updateSecretRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + environment: req.body.environment, + projectId: req.body.projectId, + secretPath: req.body.secretPath, + secretName: req.params.secretName, + type: req.body.type, + secretValue: req.body.secretValue, + skipMultilineEncoding: req.body.skipMultilineEncoding, + tagIds: req.body.tagIds, + secretReminderRepeatDays: req.body.secretReminderRepeatDays, + secretReminderRecipients: req.body.secretReminderRecipients, + secretReminderNote: req.body.secretReminderNote, + metadata: req.body.metadata, + newSecretName: req.body.newSecretName, + secretComment: req.body.secretComment, + secretMetadata: req.body.secretMetadata + }); + + if (secretOperation.type === SecretProtectionType.Approval) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: secretOperation.approval.committerUserId, + secretApprovalRequestId: secretOperation.approval.id, + secretApprovalRequestSlug: secretOperation.approval.slug, + secretPath: req.body.secretPath, + environment: req.body.environment, + secretKey: req.params.secretName, + eventType: SecretApprovalEvent.Update + } + } + }); + + return { approval: secretOperation.approval }; + } + const { secret } = secretOperation; + + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.UPDATE_SECRET, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secretId: secret.id, + secretKey: req.params.secretName, + secretVersion: secret.version, + secretMetadata: req.body.secretMetadata + } + } + }); + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretUpdated, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: 1, + projectId: req.body.projectId, + environment: req.body.environment, + secretPath: req.body.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + return { secret }; + } + }); + + server.route({ + method: "DELETE", + url: "/:secretName", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Delete secret", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: z.string().min(1).describe(RAW_SECRETS.DELETE.secretName) + }), + body: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.DELETE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.DELETE.secretPath), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.DELETE.type) + }), + response: { + 200: z.union([ + z.object({ + secret: secretRawSchema.extend({ + secretValueHidden: z.boolean() + }) + }), + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const secretOperation = await server.services.secret.deleteSecretRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + environment: req.body.environment, + projectId: req.body.projectId, + secretPath: req.body.secretPath, + secretName: req.params.secretName, + type: req.body.type + }); + if (secretOperation.type === SecretProtectionType.Approval) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: secretOperation.approval.committerUserId, + secretApprovalRequestId: secretOperation.approval.id, + secretApprovalRequestSlug: secretOperation.approval.slug, + secretPath: req.body.secretPath, + environment: req.body.environment, + secretKey: req.params.secretName, + eventType: SecretApprovalEvent.Delete + } + } + }); + + return { approval: secretOperation.approval }; + } + + const { secret } = secretOperation; + + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.DELETE_SECRET, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secretId: secret.id, + secretKey: req.params.secretName, + secretVersion: secret.version + } + } + }); + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretDeleted, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: 1, + projectId: req.body.projectId, + environment: req.body.environment, + secretPath: req.body.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + + return { secret }; + } + }); + + server.route({ + method: "POST", + url: "/move", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + body: z.object({ + projectSlug: z.string().trim(), + sourceEnvironment: z.string().trim(), + sourceSecretPath: z.string().trim().default("/").transform(removeTrailingSlash), + destinationEnvironment: z.string().trim(), + destinationSecretPath: z.string().trim().default("/").transform(removeTrailingSlash), + secretIds: z.string().array(), + shouldOverwrite: z.boolean().default(false) + }), + response: { + 200: z.object({ + isSourceUpdated: z.boolean(), + isDestinationUpdated: z.boolean() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { projectId, isSourceUpdated, isDestinationUpdated } = await server.services.secret.moveSecrets({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body + }); + + await server.services.auditLog.createAuditLog({ + projectId, + ...req.auditLogInfo, + event: { + type: EventType.MOVE_SECRETS, + metadata: { + sourceEnvironment: req.body.sourceEnvironment, + sourceSecretPath: req.body.sourceSecretPath, + destinationEnvironment: req.body.destinationEnvironment, + destinationSecretPath: req.body.destinationSecretPath, + secretIds: req.body.secretIds + } + } + }); + + return { + isSourceUpdated, + isDestinationUpdated + }; + } + }); + + server.route({ + method: "POST", + url: "/batch", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Create many secrets", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.UPDATE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.CREATE.secretPath), + secrets: z + .object({ + secretKey: SecretNameSchema.describe(RAW_SECRETS.CREATE.secretName), + secretValue: z + .string() + .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) + .describe(RAW_SECRETS.CREATE.secretValue), + secretComment: z.string().trim().optional().default("").describe(RAW_SECRETS.CREATE.secretComment), + skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.CREATE.skipMultilineEncoding), + metadata: z.record(z.string()).optional(), + secretMetadata: ResourceMetadataSchema.optional(), + tagIds: z.string().array().optional().describe(RAW_SECRETS.CREATE.tagIds) + }) + .array() + .min(1) + }), + response: { + 200: z.union([ + z.object({ + secrets: secretRawSchema.array() + }), + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { environment, secretPath, secrets: inputSecrets } = req.body; + + const secretOperation = await server.services.secret.createManySecretsRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + secretPath, + environment, + projectId: req.body.projectId, + secrets: inputSecrets + }); + if (secretOperation.type === SecretProtectionType.Approval) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: secretOperation.approval.committerUserId, + secretApprovalRequestId: secretOperation.approval.id, + secretApprovalRequestSlug: secretOperation.approval.slug, + secretPath, + environment, + secrets: inputSecrets.map((secret) => ({ + secretKey: secret.secretKey + })), + eventType: SecretApprovalEvent.CreateMany + } + } + }); + return { approval: secretOperation.approval }; + } + const { secrets } = secretOperation; + + const secretMetadataMap = new Map( + inputSecrets.map(({ secretKey, secretMetadata }) => [secretKey, secretMetadata]) + ); + + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.CREATE_SECRETS, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secrets: secrets.map((secret) => ({ + secretId: secret.id, + secretKey: secret.secretKey, + secretVersion: secret.version, + secretMetadata: secretMetadataMap.get(secret.secretKey) + })) + } + } + }); + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretCreated, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: secrets.length, + projectId: req.body.projectId, + environment: req.body.environment, + secretPath: req.body.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + return { secrets }; + } + }); + + server.route({ + method: "PATCH", + url: "/batch", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Update many secrets", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.DELETE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.UPDATE.secretPath), + mode: z + .nativeEnum(SecretUpdateMode) + .optional() + .default(SecretUpdateMode.FailOnNotFound) + .describe(RAW_SECRETS.UPDATE.mode), + secrets: z + .object({ + secretKey: SecretNameSchema.describe(RAW_SECRETS.UPDATE.secretName), + secretValue: z + .string() + .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) + .optional() + .describe(RAW_SECRETS.UPDATE.secretValue), + secretPath: z + .string() + .trim() + .transform(removeTrailingSlash) + .optional() + .describe(RAW_SECRETS.UPDATE.secretPath), + secretComment: z.string().trim().optional().describe(RAW_SECRETS.UPDATE.secretComment), + skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.UPDATE.skipMultilineEncoding), + newSecretName: SecretNameSchema.optional().describe(RAW_SECRETS.UPDATE.newSecretName), + tagIds: z.string().array().optional().describe(RAW_SECRETS.UPDATE.tagIds), + secretReminderNote: z + .string() + .max(1024, "Secret reminder note cannot exceed 1024 characters") + .optional() + .nullable() + .describe(RAW_SECRETS.UPDATE.secretReminderNote), + secretMetadata: ResourceMetadataSchema.optional(), + secretReminderRepeatDays: z + .number() + .optional() + .nullable() + .describe(RAW_SECRETS.UPDATE.secretReminderRepeatDays) + }) + .array() + .min(1) + }), + response: { + 200: z.union([ + z.object({ + secrets: secretRawSchema.extend({ secretValueHidden: z.boolean() }).array() + }), + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { environment, secretPath, secrets: inputSecrets } = req.body; + const secretOperation = await server.services.secret.updateManySecretsRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + secretPath, + environment, + projectId: req.body.projectId, + secrets: inputSecrets, + mode: req.body.mode + }); + if (secretOperation.type === SecretProtectionType.Approval) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: secretOperation.approval.committerUserId, + secretApprovalRequestId: secretOperation.approval.id, + secretApprovalRequestSlug: secretOperation.approval.slug, + secretPath, + environment, + secrets: inputSecrets.map((secret) => ({ + secretKey: secret.secretKey, + secretPath: secret.secretPath + })), + eventType: SecretApprovalEvent.UpdateMany + } + } + }); + return { approval: secretOperation.approval }; + } + const { secrets } = secretOperation; + + const secretMetadataMap = new Map( + inputSecrets.map(({ secretKey, secretMetadata }) => [secretKey, secretMetadata]) + ); + + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.UPDATE_SECRETS, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secrets: secrets + .filter((el) => el.version > 1) + .map((secret) => ({ + secretId: secret.id, + secretPath: secret.secretPath, + secretKey: secret.secretKey, + secretVersion: secret.version, + secretMetadata: secretMetadataMap.get(secret.secretKey) + })) + } + } + }); + const createdSecrets = secrets.filter((el) => el.version === 1); + if (createdSecrets.length) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.CREATE_SECRETS, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secrets: createdSecrets.map((secret) => ({ + secretId: secret.id, + secretPath: secret.secretPath, + secretKey: secret.secretKey, + secretVersion: secret.version, + secretMetadata: secretMetadataMap.get(secret.secretKey) + })) + } + } + }); + } + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretUpdated, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: secrets.length, + projectId: req.body.projectId, + environment: req.body.environment, + secretPath: req.body.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + return { secrets }; + } + }); + + server.route({ + method: "DELETE", + url: "/batch", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Delete many secrets", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.DELETE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.DELETE.secretPath), + secrets: z + .object({ + secretKey: z.string().describe(RAW_SECRETS.DELETE.secretName), + type: z.nativeEnum(SecretType).default(SecretType.Shared) + }) + .array() + .min(1) + }), + response: { + 200: z.union([ + z.object({ + secrets: secretRawSchema + .extend({ + secretValueHidden: z.boolean() + }) + .array() + }), + z.object({ approval: SecretApprovalRequestsSchema }).describe("When secret protection policy is enabled") + ]) + } + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]), + handler: async (req) => { + const { environment, secretPath, secrets: inputSecrets } = req.body; + const secretOperation = await server.services.secret.deleteManySecretsRaw({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + environment, + secretPath, + projectId: req.body.projectId, + secrets: inputSecrets + }); + if (secretOperation.type === SecretProtectionType.Approval) { + await server.services.auditLog.createAuditLog({ + projectId: req.body.projectId, + ...req.auditLogInfo, + event: { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: secretOperation.approval.committerUserId, + secretApprovalRequestId: secretOperation.approval.id, + secretApprovalRequestSlug: secretOperation.approval.slug, + secretPath, + environment, + secrets: inputSecrets.map((secret) => ({ + secretKey: secret.secretKey + })), + eventType: SecretApprovalEvent.DeleteMany + } + } + }); + + return { approval: secretOperation.approval }; + } + const { secrets } = secretOperation; + + await server.services.auditLog.createAuditLog({ + projectId: secrets[0].workspace, + ...req.auditLogInfo, + event: { + type: EventType.DELETE_SECRETS, + metadata: { + environment: req.body.environment, + secretPath: req.body.secretPath, + secrets: secrets.map((secret) => ({ + secretId: secret.id, + secretKey: secret.secretKey, + secretVersion: secret.version + })) + } + } + }); + + await server.services.telemetry.sendPostHogEvents({ + event: PostHogEventTypes.SecretDeleted, + distinctId: getTelemetryDistinctId(req), + organizationId: req.permission.orgId, + properties: { + numberOfSecrets: secrets.length, + projectId: secrets[0].workspace, + environment: req.body.environment, + secretPath: req.body.secretPath, + channel: getUserAgentType(req.headers["user-agent"]), + ...req.auditLogInfo + } + }); + return { secrets }; + } + }); + + server.route({ + method: "GET", + url: "/:secretName/secret-reference-tree", + config: { + rateLimit: secretsLimit + }, + schema: { + hide: false, + tags: [ApiDocsTags.Secrets], + description: "Get secret reference tree", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + secretName: z.string().trim().describe(RAW_SECRETS.GET_REFERENCE_TREE.secretName) + }), + querystring: z.object({ + projectId: z.string().trim().describe(RAW_SECRETS.GET_REFERENCE_TREE.projectId), + environment: z.string().trim().describe(RAW_SECRETS.GET_REFERENCE_TREE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.GET_REFERENCE_TREE.secretPath) + }), + response: { + 200: z.object({ + tree: SecretReferenceNodeTree, + value: z.string().optional() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const { secretName } = req.params; + const { secretPath, environment, projectId } = req.query; + const { tree, value } = await server.services.secret.getSecretReferenceTree({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId, + secretName, + secretPath, + environment + }); + + return { tree, value }; + } + }); + + server.route({ + method: "POST", + url: "/backfill-secret-references", + config: { + rateLimit: secretsLimit + }, + schema: { + description: "Backfill secret references", + security: [ + { + bearerAuth: [] + } + ], + body: z.object({ + projectId: z.string().trim().min(1) + }), + response: { + 200: z.object({ + message: z.string() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const { projectId } = req.body; + const message = await server.services.secret.backfillSecretReferences({ + actorId: req.permission.id, + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + projectId + }); + + return message; + } + }); +}; diff --git a/backend/src/services/external-migration/external-migration-fns/import.ts b/backend/src/services/external-migration/external-migration-fns/import.ts index 5728bf1c0..62888c5bf 100644 --- a/backend/src/services/external-migration/external-migration-fns/import.ts +++ b/backend/src/services/external-migration/external-migration-fns/import.ts @@ -55,7 +55,7 @@ export const importDataIntoInfisicalFn = async ({ actorId, actorOrgId, actorAuthMethod, - workspaceName: project.name, + projectName: project.name, createDefaultEnvs: false, tx }) diff --git a/backend/src/services/project/project-service.ts b/backend/src/services/project/project-service.ts index 2232a0411..57539f002 100644 --- a/backend/src/services/project/project-service.ts +++ b/backend/src/services/project/project-service.ts @@ -237,8 +237,8 @@ export const projectServiceFactory = ({ actorId, actorOrgId, actorAuthMethod, - workspaceName, - workspaceDescription, + projectName: workspaceName, + projectDescription: workspaceDescription, slug: projectSlug, kmsKeyId, tx: trx, @@ -254,7 +254,13 @@ export const projectServiceFactory = ({ actorAuthMethod, actorOrgId ); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace); + + if ( + permission.cannot(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace) && + permission.cannot(OrgPermissionActions.Create, OrgPermissionSubjects.Project) + ) { + throw new ForbiddenRequestError({ message: "You don't have permission to create a project" }); + } const results = await (trx || projectDAL).transaction(async (tx) => { await tx.raw("SELECT pg_advisory_xact_lock(?)", [PgSqlLock.CreateProject(organization.id)]); @@ -591,7 +597,8 @@ export const projectServiceFactory = ({ secretSharing: update.secretSharing, defaultProduct: update.defaultProduct, showSnapshotsLegacy: update.showSnapshotsLegacy, - secretDetectionIgnoreValues: update.secretDetectionIgnoreValues + secretDetectionIgnoreValues: update.secretDetectionIgnoreValues, + pitVersionLimit: update.pitVersionLimit }); return updatedProject; @@ -684,19 +691,21 @@ export const projectServiceFactory = ({ actorOrgId, actorAuthMethod, auditLogsRetentionDays, - workspaceSlug + filter }: TUpdateAuditLogsRetentionDTO) => { - const project = await projectDAL.findProjectBySlug(workspaceSlug, actorOrgId); + const project = await projectDAL.findProjectByFilter(filter); + const projectId = project.id; + if (!project) { throw new NotFoundError({ - message: `Project with slug '${workspaceSlug}' not found` + message: `Project not found` }); } const { hasRole } = await permissionService.getProjectPermission({ actor, actorId, - projectId: project.id, + projectId, actorAuthMethod, actorOrgId, actionProjectType: ActionProjectType.Any diff --git a/backend/src/services/project/project-types.ts b/backend/src/services/project/project-types.ts index bf7b633a9..74c7e95f4 100644 --- a/backend/src/services/project/project-types.ts +++ b/backend/src/services/project/project-types.ts @@ -42,12 +42,13 @@ export type TCreateProjectDTO = { actorAuthMethod: ActorAuthMethod; actorId: string; actorOrgId?: string; - workspaceName: string; - workspaceDescription?: string; + projectName: string; + projectDescription?: string; slug?: string; kmsKeyId?: string; createDefaultEnvs?: boolean; template?: string; + pitVersionLimit?: number; tx?: Knex; type?: ProjectType; }; @@ -78,7 +79,7 @@ export type TUpdateProjectVersionLimitDTO = { export type TUpdateAuditLogsRetentionDTO = { auditLogsRetentionDays: number; - workspaceSlug: string; + filter: Filter; } & Omit; export type TUpdateProjectNameDTO = { @@ -90,6 +91,7 @@ export type TUpdateProjectDTO = { update: { name?: string; description?: string; + pitVersionLimit?: number; autoCapitalization?: boolean; hasDeleteProtection?: boolean; defaultProduct?: ProjectType; diff --git a/backend/src/services/secret-folder/secret-folder-service.ts b/backend/src/services/secret-folder/secret-folder-service.ts index c5eb0adde..8e0892bd1 100644 --- a/backend/src/services/secret-folder/secret-folder-service.ts +++ b/backend/src/services/secret-folder/secret-folder-service.ts @@ -47,7 +47,7 @@ type TSecretFolderServiceFactoryDep = { folderCommitService: Pick; projectDAL: Pick; secretApprovalPolicyService: Pick; - secretV2BridgeDAL: Pick; + secretV2BridgeDAL: Pick; }; export type TSecretFolderServiceFactory = ReturnType; @@ -398,6 +398,7 @@ export const secretFolderServiceFactory = ({ await Promise.all(result.map(async (res) => snapshotService.performSnapshot(res.newFolder.parentId as string))); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); return { projectId, newFolders: result.map((res) => res.newFolder), @@ -522,6 +523,7 @@ export const secretFolderServiceFactory = ({ } await snapshotService.performSnapshot(newFolder.parentId as string); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); return { folder: { ...newFolder, path: newFolderWithFullPath.path }, old: { ...folder, path: folderWithFullPath.path } @@ -724,6 +726,7 @@ export const secretFolderServiceFactory = ({ }); await snapshotService.performSnapshot(folder.parentId as string); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); return folder; }; diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index 6bafa3ba6..8758a992e 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -2970,14 +2970,23 @@ export const secretServiceFactory = ({ actor, actorId, actorAuthMethod, - actorOrgId + actorOrgId, + projectId: inputProjectId }: TMoveSecretsDTO) => { - const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); + let project; + if (projectSlug) { + project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); + } else if (inputProjectId) { + project = await projectDAL.findById(inputProjectId); + } + if (!project) { throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); } + + const projectId = project.id; if (project.version === ProjectVersion.V3) { return secretV2BridgeService.moveSecrets({ sourceEnvironment, @@ -3170,7 +3179,7 @@ export const secretServiceFactory = ({ }); } const destinationFolderPolicy = await secretApprovalPolicyService.getSecretApprovalPolicy( - project.id, + projectId, destinationFolder.environment.slug, destinationFolder.path ); @@ -3257,7 +3266,7 @@ export const secretServiceFactory = ({ } if (locallyUpdatedSecrets.length) { await fnSecretBulkUpdate({ - projectId: project.id, + projectId, folderId: destinationFolder.id, secretVersionDAL, secretDAL, @@ -3300,7 +3309,7 @@ export const secretServiceFactory = ({ const locallyDeletedSecrets = decryptedSourceSecrets.map((el) => ({ ...el, operation: SecretOperations.Delete })); const sourceFolderPolicy = await secretApprovalPolicyService.getSecretApprovalPolicy( - project.id, + projectId, sourceFolder.environment.slug, sourceFolder.path ); diff --git a/backend/src/services/secret/secret-types.ts b/backend/src/services/secret/secret-types.ts index cd341a8b5..07f46bf1e 100644 --- a/backend/src/services/secret/secret-types.ts +++ b/backend/src/services/secret/secret-types.ts @@ -534,7 +534,8 @@ export type TSyncSecretsDTO = { }); export type TMoveSecretsDTO = { - projectSlug: string; + projectId?: string; + projectSlug?: string; sourceEnvironment: string; sourceSecretPath: string; destinationEnvironment: string; diff --git a/backend/src/services/telemetry/telemetry-types.ts b/backend/src/services/telemetry/telemetry-types.ts index 7e2027f25..a43a2f746 100644 --- a/backend/src/services/telemetry/telemetry-types.ts +++ b/backend/src/services/telemetry/telemetry-types.ts @@ -46,7 +46,7 @@ export type TSecretModifiedEvent = { properties: { numberOfSecrets: number; environment: string; - workspaceId: string; + projectId: string; secretPath: string; channel?: string; userAgent?: string; diff --git a/docs/api-reference/endpoints/deprecated/environments/create.mdx b/docs/api-reference/endpoints/deprecated/environments/create.mdx new file mode 100644 index 000000000..826dcce3d --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/environments/create.mdx @@ -0,0 +1,4 @@ +--- +title: "Create" +openapi: "POST /api/v1/workspace/{workspaceId}/environments" +--- diff --git a/docs/api-reference/endpoints/deprecated/environments/delete.mdx b/docs/api-reference/endpoints/deprecated/environments/delete.mdx new file mode 100644 index 000000000..903e58d2a --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/environments/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v1/workspace/{workspaceId}/environments/{id}" +--- diff --git a/docs/api-reference/endpoints/deprecated/environments/update.mdx b/docs/api-reference/endpoints/deprecated/environments/update.mdx new file mode 100644 index 000000000..f93968668 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/environments/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update" +openapi: "PATCH /api/v1/workspace/{workspaceId}/environments/{id}" +--- diff --git a/docs/api-reference/endpoints/deprecated/folders/create.mdx b/docs/api-reference/endpoints/deprecated/folders/create.mdx new file mode 100644 index 000000000..e1ff3004a --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/folders/create.mdx @@ -0,0 +1,4 @@ +--- +title: "Create" +openapi: "POST /api/v1/folders" +--- diff --git a/docs/api-reference/endpoints/deprecated/folders/delete.mdx b/docs/api-reference/endpoints/deprecated/folders/delete.mdx new file mode 100644 index 000000000..a106cc2eb --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/folders/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v1/folders/{folderIdOrName}" +--- diff --git a/docs/api-reference/endpoints/deprecated/folders/get-by-id.mdx b/docs/api-reference/endpoints/deprecated/folders/get-by-id.mdx new file mode 100644 index 000000000..db3c4d0cc --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/folders/get-by-id.mdx @@ -0,0 +1,4 @@ +--- +title: "Get by ID" +openapi: "GET /api/v1/folders/{id}" +--- diff --git a/docs/api-reference/endpoints/deprecated/folders/list.mdx b/docs/api-reference/endpoints/deprecated/folders/list.mdx new file mode 100644 index 000000000..f40f93273 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/folders/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v1/folders" +--- diff --git a/docs/api-reference/endpoints/deprecated/folders/update.mdx b/docs/api-reference/endpoints/deprecated/folders/update.mdx new file mode 100644 index 000000000..c54778e94 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/folders/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update" +openapi: "PATCH /api/v1/folders/{folderId}" +--- diff --git a/docs/api-reference/endpoints/organizations/workspaces.mdx b/docs/api-reference/endpoints/deprecated/organizations/projects.mdx similarity index 100% rename from docs/api-reference/endpoints/organizations/workspaces.mdx rename to docs/api-reference/endpoints/deprecated/organizations/projects.mdx diff --git a/docs/api-reference/endpoints/deprecated/project-groups/create.mdx b/docs/api-reference/endpoints/deprecated/project-groups/create.mdx new file mode 100644 index 000000000..6dd7f1a4f --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-groups/create.mdx @@ -0,0 +1,4 @@ +--- +title: "Create Project Membership" +openapi: "POST /api/v2/workspace/{projectId}/groups/{groupIdOrName}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-groups/delete.mdx b/docs/api-reference/endpoints/deprecated/project-groups/delete.mdx new file mode 100644 index 000000000..07db40d7f --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-groups/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete Project Membership" +openapi: "DELETE /api/v2/workspace/{projectId}/groups/{groupId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-groups/get-by-id.mdx b/docs/api-reference/endpoints/deprecated/project-groups/get-by-id.mdx new file mode 100644 index 000000000..611f39059 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-groups/get-by-id.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Project Membership" +openapi: "GET /api/v2/workspace/{projectId}/groups/{groupId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-groups/list.mdx b/docs/api-reference/endpoints/deprecated/project-groups/list.mdx new file mode 100644 index 000000000..1488fb6ae --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-groups/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List Project Memberships" +openapi: "GET /api/v2/workspace/{projectId}/groups" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-groups/update.mdx b/docs/api-reference/endpoints/deprecated/project-groups/update.mdx new file mode 100644 index 000000000..8b963a1d8 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-groups/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Project Membership" +openapi: "PATCH /api/v2/workspace/{projectId}/groups/{groupId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-identities/add-identity-membership.mdx b/docs/api-reference/endpoints/deprecated/project-identities/add-identity-membership.mdx new file mode 100644 index 000000000..285b1d1c4 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-identities/add-identity-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Create Identity Membership" +openapi: "POST /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-identities/delete-identity-membership.mdx b/docs/api-reference/endpoints/deprecated/project-identities/delete-identity-membership.mdx new file mode 100644 index 000000000..e2b266626 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-identities/delete-identity-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete Identity Membership" +openapi: "DELETE /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-identities/get-by-id.mdx b/docs/api-reference/endpoints/deprecated/project-identities/get-by-id.mdx new file mode 100644 index 000000000..37f4192d7 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-identities/get-by-id.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Identity by ID" +openapi: "GET /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-identities/list-identity-memberships.mdx b/docs/api-reference/endpoints/deprecated/project-identities/list-identity-memberships.mdx new file mode 100644 index 000000000..e5162e693 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-identities/list-identity-memberships.mdx @@ -0,0 +1,4 @@ +--- +title: "List Identity Memberships" +openapi: "GET /api/v2/workspace/{projectId}/identity-memberships" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-identities/update-identity-membership.mdx b/docs/api-reference/endpoints/deprecated/project-identities/update-identity-membership.mdx new file mode 100644 index 000000000..667cf7eb3 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-identities/update-identity-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Identity Membership" +openapi: "PATCH /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-roles/create.mdx b/docs/api-reference/endpoints/deprecated/project-roles/create.mdx new file mode 100644 index 000000000..97570ec36 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-roles/create.mdx @@ -0,0 +1,10 @@ +--- +title: "Create" +openapi: "POST /api/v2/workspace/{projectId}/roles" +--- + + + You can read more about the permissions field in the [permissions + documentation](/internals/permissions). + + diff --git a/docs/api-reference/endpoints/deprecated/project-roles/delete.mdx b/docs/api-reference/endpoints/deprecated/project-roles/delete.mdx new file mode 100644 index 000000000..41edfa7c3 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-roles/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v2/workspace/{projectId}/roles/{roleId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-roles/get-by-slug.mdx b/docs/api-reference/endpoints/deprecated/project-roles/get-by-slug.mdx new file mode 100644 index 000000000..dfc5c582a --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-roles/get-by-slug.mdx @@ -0,0 +1,4 @@ +--- +title: "Get By Slug" +openapi: "GET /api/v2/workspace/{projectId}/roles/slug/{roleSlug}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-roles/list.mdx b/docs/api-reference/endpoints/deprecated/project-roles/list.mdx new file mode 100644 index 000000000..8d8dc10c1 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-roles/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v2/workspace/{projectId}/roles" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-roles/update.mdx b/docs/api-reference/endpoints/deprecated/project-roles/update.mdx new file mode 100644 index 000000000..662d5e617 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-roles/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update" +openapi: "PATCH /api/v2/workspace/{projectId}/roles/{roleId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-users/delete-membership.mdx b/docs/api-reference/endpoints/deprecated/project-users/delete-membership.mdx new file mode 100644 index 000000000..1995e4726 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-users/delete-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete User Membership" +openapi: "DELETE /api/v1/workspace/{workspaceId}/memberships/{membershipId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/project-users/get-by-username.mdx b/docs/api-reference/endpoints/deprecated/project-users/get-by-username.mdx new file mode 100644 index 000000000..ec69d4947 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-users/get-by-username.mdx @@ -0,0 +1,4 @@ +--- +title: "Get By Username" +openapi: "POST /api/v1/workspace/{workspaceId}/memberships/details" +--- diff --git a/docs/api-reference/endpoints/project-users/invite-member-to-workspace.mdx b/docs/api-reference/endpoints/deprecated/project-users/invite-member-to-project.mdx similarity index 100% rename from docs/api-reference/endpoints/project-users/invite-member-to-workspace.mdx rename to docs/api-reference/endpoints/deprecated/project-users/invite-member-to-project.mdx diff --git a/docs/api-reference/endpoints/deprecated/project-users/memberships.mdx b/docs/api-reference/endpoints/deprecated/project-users/memberships.mdx new file mode 100644 index 000000000..3c4735f94 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-users/memberships.mdx @@ -0,0 +1,4 @@ +--- +title: "Get User Memberships" +openapi: "GET /api/v1/workspace/{workspaceId}/memberships" +--- diff --git a/docs/api-reference/endpoints/project-users/remove-member-from-workspace.mdx b/docs/api-reference/endpoints/deprecated/project-users/remove-member-from-project.mdx similarity index 100% rename from docs/api-reference/endpoints/project-users/remove-member-from-workspace.mdx rename to docs/api-reference/endpoints/deprecated/project-users/remove-member-from-project.mdx diff --git a/docs/api-reference/endpoints/deprecated/project-users/update-membership.mdx b/docs/api-reference/endpoints/deprecated/project-users/update-membership.mdx new file mode 100644 index 000000000..9a7aa600f --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/project-users/update-membership.mdx @@ -0,0 +1,4 @@ +--- +title: "Update User Membership" +openapi: "PATCH /api/v1/workspace/{workspaceId}/memberships/{membershipId}" +--- diff --git a/docs/api-reference/endpoints/workspaces/create-workspace.mdx b/docs/api-reference/endpoints/deprecated/projects/create-project.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/create-workspace.mdx rename to docs/api-reference/endpoints/deprecated/projects/create-project.mdx diff --git a/docs/api-reference/endpoints/workspaces/delete-workspace.mdx b/docs/api-reference/endpoints/deprecated/projects/delete-project.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/delete-workspace.mdx rename to docs/api-reference/endpoints/deprecated/projects/delete-project.mdx diff --git a/docs/api-reference/endpoints/workspaces/get-workspace-by-slug.mdx b/docs/api-reference/endpoints/deprecated/projects/get-project-by-slug.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/get-workspace-by-slug.mdx rename to docs/api-reference/endpoints/deprecated/projects/get-project-by-slug.mdx diff --git a/docs/api-reference/endpoints/workspaces/get-workspace.mdx b/docs/api-reference/endpoints/deprecated/projects/get-project.mdx similarity index 94% rename from docs/api-reference/endpoints/workspaces/get-workspace.mdx rename to docs/api-reference/endpoints/deprecated/projects/get-project.mdx index edd0a0276..a27d41b43 100644 --- a/docs/api-reference/endpoints/workspaces/get-workspace.mdx +++ b/docs/api-reference/endpoints/deprecated/projects/get-project.mdx @@ -1,4 +1,4 @@ --- title: "Get Project" openapi: "GET /api/v1/workspace/{workspaceId}" ---- \ No newline at end of file +--- diff --git a/docs/api-reference/endpoints/workspaces/workspace-key.mdx b/docs/api-reference/endpoints/deprecated/projects/project-key.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/workspace-key.mdx rename to docs/api-reference/endpoints/deprecated/projects/project-key.mdx diff --git a/docs/api-reference/endpoints/workspaces/update-workspace.mdx b/docs/api-reference/endpoints/deprecated/projects/project-workspace.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/update-workspace.mdx rename to docs/api-reference/endpoints/deprecated/projects/project-workspace.mdx diff --git a/docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx b/docs/api-reference/endpoints/deprecated/projects/rollback-snapshot.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/rollback-snapshot.mdx rename to docs/api-reference/endpoints/deprecated/projects/rollback-snapshot.mdx diff --git a/docs/api-reference/endpoints/workspaces/secret-snapshots.mdx b/docs/api-reference/endpoints/deprecated/projects/secret-snapshots.mdx similarity index 100% rename from docs/api-reference/endpoints/workspaces/secret-snapshots.mdx rename to docs/api-reference/endpoints/deprecated/projects/secret-snapshots.mdx diff --git a/docs/api-reference/endpoints/deprecated/projects/update-project.mdx b/docs/api-reference/endpoints/deprecated/projects/update-project.mdx new file mode 100644 index 000000000..699e3e3af --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/projects/update-project.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Project" +openapi: "PATCH /api/v1/workspace/{workspaceId}" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/deprecated/secret-imports/create.mdx b/docs/api-reference/endpoints/deprecated/secret-imports/create.mdx new file mode 100644 index 000000000..3abfb320f --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-imports/create.mdx @@ -0,0 +1,4 @@ +--- +title: "Create" +openapi: "POST /api/v1/secret-imports" +--- diff --git a/docs/api-reference/endpoints/deprecated/secret-imports/delete.mdx b/docs/api-reference/endpoints/deprecated/secret-imports/delete.mdx new file mode 100644 index 000000000..cfa5960b1 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-imports/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v1/secret-imports/{secretImportId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/secret-imports/list.mdx b/docs/api-reference/endpoints/deprecated/secret-imports/list.mdx new file mode 100644 index 000000000..580d4be8d --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-imports/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v1/secret-imports" +--- diff --git a/docs/api-reference/endpoints/deprecated/secret-imports/update.mdx b/docs/api-reference/endpoints/deprecated/secret-imports/update.mdx new file mode 100644 index 000000000..f21133223 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-imports/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update" +openapi: "PATCH /api/v1/secret-imports/{secretImportId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/secret-tags/create.mdx b/docs/api-reference/endpoints/deprecated/secret-tags/create.mdx new file mode 100644 index 000000000..82d0eed17 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-tags/create.mdx @@ -0,0 +1,4 @@ +--- +title: "Create" +openapi: "POST /api/v1/workspace/{projectId}/tags" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/deprecated/secret-tags/delete.mdx b/docs/api-reference/endpoints/deprecated/secret-tags/delete.mdx new file mode 100644 index 000000000..cc98f03c2 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-tags/delete.mdx @@ -0,0 +1,4 @@ +--- +title: "Delete" +openapi: "DELETE /api/v1/workspace/{projectId}/tags/{tagId}" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/deprecated/secret-tags/get-by-id.mdx b/docs/api-reference/endpoints/deprecated/secret-tags/get-by-id.mdx new file mode 100644 index 000000000..de02fe133 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-tags/get-by-id.mdx @@ -0,0 +1,4 @@ +--- +title: "Get By ID" +openapi: "GET /api/v1/workspace/{projectId}/tags/{tagId}" +--- diff --git a/docs/api-reference/endpoints/deprecated/secret-tags/get-by-slug.mdx b/docs/api-reference/endpoints/deprecated/secret-tags/get-by-slug.mdx new file mode 100644 index 000000000..91eab730f --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-tags/get-by-slug.mdx @@ -0,0 +1,4 @@ +--- +title: "Get By Slug" +openapi: "GET /api/v1/workspace/{projectId}/tags/slug/{tagSlug}" +--- diff --git a/docs/api-reference/endpoints/deprecated/secret-tags/list.mdx b/docs/api-reference/endpoints/deprecated/secret-tags/list.mdx new file mode 100644 index 000000000..c4a940f77 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-tags/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v1/workspace/{projectId}/tags" +--- \ No newline at end of file diff --git a/docs/api-reference/endpoints/deprecated/secret-tags/update.mdx b/docs/api-reference/endpoints/deprecated/secret-tags/update.mdx new file mode 100644 index 000000000..b9c290db8 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secret-tags/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update" +openapi: "PATCH /api/v1/workspace/{projectId}/tags/{tagId}" +--- diff --git a/docs/api-reference/endpoints/secrets/attach-tags.mdx b/docs/api-reference/endpoints/deprecated/secrets/attach-tags.mdx similarity index 100% rename from docs/api-reference/endpoints/secrets/attach-tags.mdx rename to docs/api-reference/endpoints/deprecated/secrets/attach-tags.mdx diff --git a/docs/api-reference/endpoints/deprecated/secrets/create-many.mdx b/docs/api-reference/endpoints/deprecated/secrets/create-many.mdx new file mode 100644 index 000000000..227c5470d --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/create-many.mdx @@ -0,0 +1,5 @@ +--- +title: "Bulk Create" +openapi: "POST /api/v3/secrets/batch/raw" +--- + diff --git a/docs/api-reference/endpoints/deprecated/secrets/create.mdx b/docs/api-reference/endpoints/deprecated/secrets/create.mdx new file mode 100644 index 000000000..afee0a719 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/create.mdx @@ -0,0 +1,5 @@ +--- +title: "Create" +openapi: "POST /api/v3/secrets/raw/{secretName}" +--- + diff --git a/docs/api-reference/endpoints/deprecated/secrets/delete-many.mdx b/docs/api-reference/endpoints/deprecated/secrets/delete-many.mdx new file mode 100644 index 000000000..57c8588d8 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/delete-many.mdx @@ -0,0 +1,5 @@ +--- +title: "Bulk Delete" +openapi: "DELETE /api/v3/secrets/batch/raw" +--- + diff --git a/docs/api-reference/endpoints/deprecated/secrets/delete.mdx b/docs/api-reference/endpoints/deprecated/secrets/delete.mdx new file mode 100644 index 000000000..ef3abc722 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/delete.mdx @@ -0,0 +1,5 @@ +--- +title: "Delete" +openapi: "DELETE /api/v3/secrets/raw/{secretName}" +--- + diff --git a/docs/api-reference/endpoints/secrets/detach-tags.mdx b/docs/api-reference/endpoints/deprecated/secrets/detach-tags.mdx similarity index 100% rename from docs/api-reference/endpoints/secrets/detach-tags.mdx rename to docs/api-reference/endpoints/deprecated/secrets/detach-tags.mdx diff --git a/docs/api-reference/endpoints/deprecated/secrets/list.mdx b/docs/api-reference/endpoints/deprecated/secrets/list.mdx new file mode 100644 index 000000000..4808f6690 --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/list.mdx @@ -0,0 +1,4 @@ +--- +title: "List" +openapi: "GET /api/v3/secrets/raw" +--- diff --git a/docs/api-reference/endpoints/deprecated/secrets/read.mdx b/docs/api-reference/endpoints/deprecated/secrets/read.mdx new file mode 100644 index 000000000..6af308e0f --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/read.mdx @@ -0,0 +1,5 @@ +--- +title: "Retrieve" +openapi: "GET /api/v3/secrets/raw/{secretName}" +--- + diff --git a/docs/api-reference/endpoints/deprecated/secrets/update-many.mdx b/docs/api-reference/endpoints/deprecated/secrets/update-many.mdx new file mode 100644 index 000000000..7586d91bc --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/update-many.mdx @@ -0,0 +1,5 @@ +--- +title: "Bulk Update" +openapi: "PATCH /api/v3/secrets/batch/raw" +--- + diff --git a/docs/api-reference/endpoints/deprecated/secrets/update.mdx b/docs/api-reference/endpoints/deprecated/secrets/update.mdx new file mode 100644 index 000000000..ce68c492e --- /dev/null +++ b/docs/api-reference/endpoints/deprecated/secrets/update.mdx @@ -0,0 +1,4 @@ +--- +title: "Update" +openapi: "PATCH /api/v3/secrets/raw/{secretName}" +--- diff --git a/docs/api-reference/endpoints/environments/create.mdx b/docs/api-reference/endpoints/environments/create.mdx index 826dcce3d..c7f9b0658 100644 --- a/docs/api-reference/endpoints/environments/create.mdx +++ b/docs/api-reference/endpoints/environments/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/workspace/{workspaceId}/environments" +openapi: "POST /api/v1/projects/{projectId}/environments" --- diff --git a/docs/api-reference/endpoints/environments/delete.mdx b/docs/api-reference/endpoints/environments/delete.mdx index 903e58d2a..2d2419255 100644 --- a/docs/api-reference/endpoints/environments/delete.mdx +++ b/docs/api-reference/endpoints/environments/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/workspace/{workspaceId}/environments/{id}" +openapi: "DELETE /api/v1/projects/{projectId}/environments/{id}" --- diff --git a/docs/api-reference/endpoints/environments/update.mdx b/docs/api-reference/endpoints/environments/update.mdx index f93968668..1583f5220 100644 --- a/docs/api-reference/endpoints/environments/update.mdx +++ b/docs/api-reference/endpoints/environments/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/workspace/{workspaceId}/environments/{id}" +openapi: "PATCH /api/v1/projects/{projectId}/environments/{id}" --- diff --git a/docs/api-reference/endpoints/folders/create.mdx b/docs/api-reference/endpoints/folders/create.mdx index e1ff3004a..13c4abea2 100644 --- a/docs/api-reference/endpoints/folders/create.mdx +++ b/docs/api-reference/endpoints/folders/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/folders" +openapi: "POST /api/v2/folders" --- diff --git a/docs/api-reference/endpoints/folders/delete.mdx b/docs/api-reference/endpoints/folders/delete.mdx index a106cc2eb..71ba9684c 100644 --- a/docs/api-reference/endpoints/folders/delete.mdx +++ b/docs/api-reference/endpoints/folders/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/folders/{folderIdOrName}" +openapi: "DELETE /api/v2/folders/{folderIdOrName}" --- diff --git a/docs/api-reference/endpoints/folders/get-by-id.mdx b/docs/api-reference/endpoints/folders/get-by-id.mdx index db3c4d0cc..ebfda35da 100644 --- a/docs/api-reference/endpoints/folders/get-by-id.mdx +++ b/docs/api-reference/endpoints/folders/get-by-id.mdx @@ -1,4 +1,4 @@ --- title: "Get by ID" -openapi: "GET /api/v1/folders/{id}" +openapi: "GET /api/v2/folders/{id}" --- diff --git a/docs/api-reference/endpoints/folders/list.mdx b/docs/api-reference/endpoints/folders/list.mdx index f40f93273..1d3a10ed8 100644 --- a/docs/api-reference/endpoints/folders/list.mdx +++ b/docs/api-reference/endpoints/folders/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v1/folders" +openapi: "GET /api/v2/folders" --- diff --git a/docs/api-reference/endpoints/folders/update.mdx b/docs/api-reference/endpoints/folders/update.mdx index c54778e94..969833a04 100644 --- a/docs/api-reference/endpoints/folders/update.mdx +++ b/docs/api-reference/endpoints/folders/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/folders/{folderId}" +openapi: "PATCH /api/v2/folders/{folderId}" --- diff --git a/docs/api-reference/endpoints/project-groups/create.mdx b/docs/api-reference/endpoints/project-groups/create.mdx index 6dd7f1a4f..c40c506a6 100644 --- a/docs/api-reference/endpoints/project-groups/create.mdx +++ b/docs/api-reference/endpoints/project-groups/create.mdx @@ -1,4 +1,4 @@ --- title: "Create Project Membership" -openapi: "POST /api/v2/workspace/{projectId}/groups/{groupIdOrName}" +openapi: "POST /api/v1/projects/{projectId}/groups/{groupIdOrName}" --- diff --git a/docs/api-reference/endpoints/project-groups/delete.mdx b/docs/api-reference/endpoints/project-groups/delete.mdx index 07db40d7f..450e05501 100644 --- a/docs/api-reference/endpoints/project-groups/delete.mdx +++ b/docs/api-reference/endpoints/project-groups/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete Project Membership" -openapi: "DELETE /api/v2/workspace/{projectId}/groups/{groupId}" +openapi: "DELETE /api/v1/projects/{projectId}/groups/{groupId}" --- diff --git a/docs/api-reference/endpoints/project-groups/get-by-id.mdx b/docs/api-reference/endpoints/project-groups/get-by-id.mdx index 611f39059..89aa6ebac 100644 --- a/docs/api-reference/endpoints/project-groups/get-by-id.mdx +++ b/docs/api-reference/endpoints/project-groups/get-by-id.mdx @@ -1,4 +1,4 @@ --- title: "Get Project Membership" -openapi: "GET /api/v2/workspace/{projectId}/groups/{groupId}" +openapi: "GET /api/v1/projects/{projectId}/groups/{groupId}" --- diff --git a/docs/api-reference/endpoints/project-groups/list.mdx b/docs/api-reference/endpoints/project-groups/list.mdx index 1488fb6ae..90b4f957a 100644 --- a/docs/api-reference/endpoints/project-groups/list.mdx +++ b/docs/api-reference/endpoints/project-groups/list.mdx @@ -1,4 +1,4 @@ --- title: "List Project Memberships" -openapi: "GET /api/v2/workspace/{projectId}/groups" +openapi: "GET /api/v1/projects/{projectId}/groups" --- diff --git a/docs/api-reference/endpoints/project-groups/update.mdx b/docs/api-reference/endpoints/project-groups/update.mdx index 8b963a1d8..029815673 100644 --- a/docs/api-reference/endpoints/project-groups/update.mdx +++ b/docs/api-reference/endpoints/project-groups/update.mdx @@ -1,4 +1,4 @@ --- title: "Update Project Membership" -openapi: "PATCH /api/v2/workspace/{projectId}/groups/{groupId}" +openapi: "PATCH /api/v1/projects/{projectId}/groups/{groupId}" --- diff --git a/docs/api-reference/endpoints/project-identities/add-identity-membership.mdx b/docs/api-reference/endpoints/project-identities/add-identity-membership.mdx index 285b1d1c4..8b0122efd 100644 --- a/docs/api-reference/endpoints/project-identities/add-identity-membership.mdx +++ b/docs/api-reference/endpoints/project-identities/add-identity-membership.mdx @@ -1,4 +1,4 @@ --- title: "Create Identity Membership" -openapi: "POST /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +openapi: "POST /api/v1/projects/{projectId}/identity-memberships/{identityId}" --- diff --git a/docs/api-reference/endpoints/project-identities/delete-identity-membership.mdx b/docs/api-reference/endpoints/project-identities/delete-identity-membership.mdx index e2b266626..10c56e5ec 100644 --- a/docs/api-reference/endpoints/project-identities/delete-identity-membership.mdx +++ b/docs/api-reference/endpoints/project-identities/delete-identity-membership.mdx @@ -1,4 +1,4 @@ --- title: "Delete Identity Membership" -openapi: "DELETE /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +openapi: "DELETE /api/v1/projects/{projectId}/identity-memberships/{identityId}" --- diff --git a/docs/api-reference/endpoints/project-identities/get-by-id.mdx b/docs/api-reference/endpoints/project-identities/get-by-id.mdx index 37f4192d7..801b0d422 100644 --- a/docs/api-reference/endpoints/project-identities/get-by-id.mdx +++ b/docs/api-reference/endpoints/project-identities/get-by-id.mdx @@ -1,4 +1,4 @@ --- title: "Get Identity by ID" -openapi: "GET /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +openapi: "GET /api/v1/projects/{projectId}/identity-memberships/{identityId}" --- diff --git a/docs/api-reference/endpoints/project-identities/list-identity-memberships.mdx b/docs/api-reference/endpoints/project-identities/list-identity-memberships.mdx index e5162e693..8673350fa 100644 --- a/docs/api-reference/endpoints/project-identities/list-identity-memberships.mdx +++ b/docs/api-reference/endpoints/project-identities/list-identity-memberships.mdx @@ -1,4 +1,4 @@ --- title: "List Identity Memberships" -openapi: "GET /api/v2/workspace/{projectId}/identity-memberships" +openapi: "GET /api/v1/projects/{projectId}/identity-memberships" --- diff --git a/docs/api-reference/endpoints/project-identities/update-identity-membership.mdx b/docs/api-reference/endpoints/project-identities/update-identity-membership.mdx index 667cf7eb3..ef34363d6 100644 --- a/docs/api-reference/endpoints/project-identities/update-identity-membership.mdx +++ b/docs/api-reference/endpoints/project-identities/update-identity-membership.mdx @@ -1,4 +1,4 @@ --- title: "Update Identity Membership" -openapi: "PATCH /api/v2/workspace/{projectId}/identity-memberships/{identityId}" +openapi: "PATCH /api/v1/projects/{projectId}/identity-memberships/{identityId}" --- diff --git a/docs/api-reference/endpoints/project-roles/create.mdx b/docs/api-reference/endpoints/project-roles/create.mdx index 97570ec36..1d3f9eb51 100644 --- a/docs/api-reference/endpoints/project-roles/create.mdx +++ b/docs/api-reference/endpoints/project-roles/create.mdx @@ -1,10 +1,9 @@ --- title: "Create" -openapi: "POST /api/v2/workspace/{projectId}/roles" +openapi: "POST /api/v1/projects/{projectId}/roles" --- You can read more about the permissions field in the [permissions documentation](/internals/permissions). - diff --git a/docs/api-reference/endpoints/project-roles/delete.mdx b/docs/api-reference/endpoints/project-roles/delete.mdx index 41edfa7c3..7b162c6da 100644 --- a/docs/api-reference/endpoints/project-roles/delete.mdx +++ b/docs/api-reference/endpoints/project-roles/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v2/workspace/{projectId}/roles/{roleId}" +openapi: "DELETE /api/v1/projects/{projectId}/roles/{roleId}" --- diff --git a/docs/api-reference/endpoints/project-roles/get-by-slug.mdx b/docs/api-reference/endpoints/project-roles/get-by-slug.mdx index dfc5c582a..adfac8cd3 100644 --- a/docs/api-reference/endpoints/project-roles/get-by-slug.mdx +++ b/docs/api-reference/endpoints/project-roles/get-by-slug.mdx @@ -1,4 +1,4 @@ --- title: "Get By Slug" -openapi: "GET /api/v2/workspace/{projectId}/roles/slug/{roleSlug}" +openapi: "GET /api/v1/projects/{projectId}/roles/slug/{roleSlug}" --- diff --git a/docs/api-reference/endpoints/project-roles/list.mdx b/docs/api-reference/endpoints/project-roles/list.mdx index 8d8dc10c1..df6164370 100644 --- a/docs/api-reference/endpoints/project-roles/list.mdx +++ b/docs/api-reference/endpoints/project-roles/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v2/workspace/{projectId}/roles" +openapi: "GET /api/v1/projects/{projectId}/roles" --- diff --git a/docs/api-reference/endpoints/project-roles/update.mdx b/docs/api-reference/endpoints/project-roles/update.mdx index 662d5e617..56ac34f8b 100644 --- a/docs/api-reference/endpoints/project-roles/update.mdx +++ b/docs/api-reference/endpoints/project-roles/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v2/workspace/{projectId}/roles/{roleId}" +openapi: "PATCH /api/v1/projects/{projectId}/roles/{roleId}" --- diff --git a/docs/api-reference/endpoints/project-users/delete-membership.mdx b/docs/api-reference/endpoints/project-users/delete-membership.mdx index 1995e4726..5c87e94af 100644 --- a/docs/api-reference/endpoints/project-users/delete-membership.mdx +++ b/docs/api-reference/endpoints/project-users/delete-membership.mdx @@ -1,4 +1,4 @@ --- title: "Delete User Membership" -openapi: "DELETE /api/v1/workspace/{workspaceId}/memberships/{membershipId}" +openapi: "DELETE /api/v1/projects/{projectId}/memberships/{membershipId}" --- diff --git a/docs/api-reference/endpoints/project-users/get-by-username.mdx b/docs/api-reference/endpoints/project-users/get-by-username.mdx index ec69d4947..5e4916b8e 100644 --- a/docs/api-reference/endpoints/project-users/get-by-username.mdx +++ b/docs/api-reference/endpoints/project-users/get-by-username.mdx @@ -1,4 +1,4 @@ --- title: "Get By Username" -openapi: "POST /api/v1/workspace/{workspaceId}/memberships/details" +openapi: "POST /api/v1/projects/{projectId}/memberships/details" --- diff --git a/docs/api-reference/endpoints/project-users/invite-member-to-project.mdx b/docs/api-reference/endpoints/project-users/invite-member-to-project.mdx new file mode 100644 index 000000000..c6fda8a09 --- /dev/null +++ b/docs/api-reference/endpoints/project-users/invite-member-to-project.mdx @@ -0,0 +1,4 @@ +--- +title: "Invite Member" +openapi: "POST /api/v1/projects/{projectId}/memberships" +--- diff --git a/docs/api-reference/endpoints/project-users/memberships.mdx b/docs/api-reference/endpoints/project-users/memberships.mdx index 3c4735f94..dd79667fe 100644 --- a/docs/api-reference/endpoints/project-users/memberships.mdx +++ b/docs/api-reference/endpoints/project-users/memberships.mdx @@ -1,4 +1,4 @@ --- title: "Get User Memberships" -openapi: "GET /api/v1/workspace/{workspaceId}/memberships" +openapi: "GET /api/v1/projects/{projectId}/memberships" --- diff --git a/docs/api-reference/endpoints/project-users/remove-member-from-project.mdx b/docs/api-reference/endpoints/project-users/remove-member-from-project.mdx new file mode 100644 index 000000000..8646aa158 --- /dev/null +++ b/docs/api-reference/endpoints/project-users/remove-member-from-project.mdx @@ -0,0 +1,4 @@ +--- +title: "Remove Member" +openapi: "DELETE /api/v1/projects/{projectId}/memberships" +--- diff --git a/docs/api-reference/endpoints/project-users/update-membership.mdx b/docs/api-reference/endpoints/project-users/update-membership.mdx index 9a7aa600f..5f1edcf0a 100644 --- a/docs/api-reference/endpoints/project-users/update-membership.mdx +++ b/docs/api-reference/endpoints/project-users/update-membership.mdx @@ -1,4 +1,4 @@ --- title: "Update User Membership" -openapi: "PATCH /api/v1/workspace/{workspaceId}/memberships/{membershipId}" +openapi: "PATCH /api/v1/projects/{projectId}/memberships/{membershipId}" --- diff --git a/docs/api-reference/endpoints/projects/create-project.mdx b/docs/api-reference/endpoints/projects/create-project.mdx new file mode 100644 index 000000000..7ee1caff8 --- /dev/null +++ b/docs/api-reference/endpoints/projects/create-project.mdx @@ -0,0 +1,4 @@ +--- +title: "Create Project" +openapi: "POST /api/v1/projects" +--- diff --git a/docs/api-reference/endpoints/projects/delete-project.mdx b/docs/api-reference/endpoints/projects/delete-project.mdx new file mode 100644 index 000000000..eff96ded5 --- /dev/null +++ b/docs/api-reference/endpoints/projects/delete-project.mdx @@ -0,0 +1,8 @@ +--- +title: "Delete Project" +openapi: "DELETE /api/v1/projects/{projectId}" +--- + + + This operation is irreversible. All data associated with the project will be deleted. Please use with caution. + diff --git a/docs/api-reference/endpoints/projects/get-project-by-slug.mdx b/docs/api-reference/endpoints/projects/get-project-by-slug.mdx new file mode 100644 index 000000000..9bcccc31e --- /dev/null +++ b/docs/api-reference/endpoints/projects/get-project-by-slug.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Project By Slug" +openapi: "GET /api/v1/projects/slug/{slug}" +--- diff --git a/docs/api-reference/endpoints/projects/get-project.mdx b/docs/api-reference/endpoints/projects/get-project.mdx new file mode 100644 index 000000000..6ed92833e --- /dev/null +++ b/docs/api-reference/endpoints/projects/get-project.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Project" +openapi: "GET /api/v1/projects/{projectId}" +--- diff --git a/docs/api-reference/endpoints/projects/list-projects.mdx b/docs/api-reference/endpoints/projects/list-projects.mdx new file mode 100644 index 000000000..5017023a1 --- /dev/null +++ b/docs/api-reference/endpoints/projects/list-projects.mdx @@ -0,0 +1,4 @@ +--- +title: "List Projects" +openapi: "GET /api/v1/projects" +--- diff --git a/docs/api-reference/endpoints/projects/rollback-snapshot.mdx b/docs/api-reference/endpoints/projects/rollback-snapshot.mdx new file mode 100644 index 000000000..527c861b2 --- /dev/null +++ b/docs/api-reference/endpoints/projects/rollback-snapshot.mdx @@ -0,0 +1,4 @@ +--- +title: "Roll Back to Snapshot" +openapi: "POST /api/v1/secret-snapshot/{secretSnapshotId}/rollback" +--- diff --git a/docs/api-reference/endpoints/projects/secret-snapshots.mdx b/docs/api-reference/endpoints/projects/secret-snapshots.mdx new file mode 100644 index 000000000..182e61507 --- /dev/null +++ b/docs/api-reference/endpoints/projects/secret-snapshots.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Snapshots" +openapi: "GET /api/v1/projects/{projectId}/secret-snapshots" +--- diff --git a/docs/api-reference/endpoints/projects/update-project.mdx b/docs/api-reference/endpoints/projects/update-project.mdx new file mode 100644 index 000000000..99fcc7b76 --- /dev/null +++ b/docs/api-reference/endpoints/projects/update-project.mdx @@ -0,0 +1,4 @@ +--- +title: "Update Project" +openapi: "PATCH /api/v1/projects/{projectId}" +--- diff --git a/docs/api-reference/endpoints/secret-imports/create.mdx b/docs/api-reference/endpoints/secret-imports/create.mdx index 3abfb320f..f072e59a4 100644 --- a/docs/api-reference/endpoints/secret-imports/create.mdx +++ b/docs/api-reference/endpoints/secret-imports/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/secret-imports" +openapi: "POST /api/v2/secret-imports" --- diff --git a/docs/api-reference/endpoints/secret-imports/delete.mdx b/docs/api-reference/endpoints/secret-imports/delete.mdx index cfa5960b1..d0b35426b 100644 --- a/docs/api-reference/endpoints/secret-imports/delete.mdx +++ b/docs/api-reference/endpoints/secret-imports/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/secret-imports/{secretImportId}" +openapi: "DELETE /api/v2/secret-imports/{secretImportId}" --- diff --git a/docs/api-reference/endpoints/secret-imports/list.mdx b/docs/api-reference/endpoints/secret-imports/list.mdx index 580d4be8d..1cf3e1386 100644 --- a/docs/api-reference/endpoints/secret-imports/list.mdx +++ b/docs/api-reference/endpoints/secret-imports/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v1/secret-imports" +openapi: "GET /api/v2/secret-imports" --- diff --git a/docs/api-reference/endpoints/secret-imports/update.mdx b/docs/api-reference/endpoints/secret-imports/update.mdx index f21133223..146fcd76b 100644 --- a/docs/api-reference/endpoints/secret-imports/update.mdx +++ b/docs/api-reference/endpoints/secret-imports/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/secret-imports/{secretImportId}" +openapi: "PATCH /api/v2/secret-imports/{secretImportId}" --- diff --git a/docs/api-reference/endpoints/secret-tags/create.mdx b/docs/api-reference/endpoints/secret-tags/create.mdx index 82d0eed17..d4c587979 100644 --- a/docs/api-reference/endpoints/secret-tags/create.mdx +++ b/docs/api-reference/endpoints/secret-tags/create.mdx @@ -1,4 +1,4 @@ --- title: "Create" -openapi: "POST /api/v1/workspace/{projectId}/tags" ---- \ No newline at end of file +openapi: "POST /api/v1/projects/{projectId}/tags" +--- diff --git a/docs/api-reference/endpoints/secret-tags/delete.mdx b/docs/api-reference/endpoints/secret-tags/delete.mdx index cc98f03c2..121d6816c 100644 --- a/docs/api-reference/endpoints/secret-tags/delete.mdx +++ b/docs/api-reference/endpoints/secret-tags/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/workspace/{projectId}/tags/{tagId}" ---- \ No newline at end of file +openapi: "DELETE /api/v1/projects/{projectId}/tags/{tagId}" +--- diff --git a/docs/api-reference/endpoints/secret-tags/get-by-id.mdx b/docs/api-reference/endpoints/secret-tags/get-by-id.mdx index de02fe133..7e1fa8d7f 100644 --- a/docs/api-reference/endpoints/secret-tags/get-by-id.mdx +++ b/docs/api-reference/endpoints/secret-tags/get-by-id.mdx @@ -1,4 +1,4 @@ --- title: "Get By ID" -openapi: "GET /api/v1/workspace/{projectId}/tags/{tagId}" +openapi: "GET /api/v1/projects/{projectId}/tags/{tagId}" --- diff --git a/docs/api-reference/endpoints/secret-tags/get-by-slug.mdx b/docs/api-reference/endpoints/secret-tags/get-by-slug.mdx index 91eab730f..c012c97d4 100644 --- a/docs/api-reference/endpoints/secret-tags/get-by-slug.mdx +++ b/docs/api-reference/endpoints/secret-tags/get-by-slug.mdx @@ -1,4 +1,4 @@ --- title: "Get By Slug" -openapi: "GET /api/v1/workspace/{projectId}/tags/slug/{tagSlug}" +openapi: "GET /api/v1/projects/{projectId}/tags/slug/{tagSlug}" --- diff --git a/docs/api-reference/endpoints/secret-tags/list.mdx b/docs/api-reference/endpoints/secret-tags/list.mdx index c4a940f77..b7e1eca74 100644 --- a/docs/api-reference/endpoints/secret-tags/list.mdx +++ b/docs/api-reference/endpoints/secret-tags/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v1/workspace/{projectId}/tags" ---- \ No newline at end of file +openapi: "GET /api/v1/projects/{projectId}/tags" +--- diff --git a/docs/api-reference/endpoints/secret-tags/update.mdx b/docs/api-reference/endpoints/secret-tags/update.mdx index b9c290db8..b20ce49f4 100644 --- a/docs/api-reference/endpoints/secret-tags/update.mdx +++ b/docs/api-reference/endpoints/secret-tags/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/workspace/{projectId}/tags/{tagId}" +openapi: "PATCH /api/v1/projects/{projectId}/tags/{tagId}" --- diff --git a/docs/api-reference/endpoints/secrets/create-many.mdx b/docs/api-reference/endpoints/secrets/create-many.mdx index 227c5470d..e3d30aef8 100644 --- a/docs/api-reference/endpoints/secrets/create-many.mdx +++ b/docs/api-reference/endpoints/secrets/create-many.mdx @@ -1,5 +1,4 @@ --- title: "Bulk Create" -openapi: "POST /api/v3/secrets/batch/raw" +openapi: "POST /api/v4/secrets/batch" --- - diff --git a/docs/api-reference/endpoints/secrets/create.mdx b/docs/api-reference/endpoints/secrets/create.mdx index afee0a719..c04dcf9f4 100644 --- a/docs/api-reference/endpoints/secrets/create.mdx +++ b/docs/api-reference/endpoints/secrets/create.mdx @@ -1,5 +1,4 @@ --- title: "Create" -openapi: "POST /api/v3/secrets/raw/{secretName}" +openapi: "POST /api/v4/secrets/{secretName}" --- - diff --git a/docs/api-reference/endpoints/secrets/delete-many.mdx b/docs/api-reference/endpoints/secrets/delete-many.mdx index 57c8588d8..49491c3b9 100644 --- a/docs/api-reference/endpoints/secrets/delete-many.mdx +++ b/docs/api-reference/endpoints/secrets/delete-many.mdx @@ -1,5 +1,4 @@ --- title: "Bulk Delete" -openapi: "DELETE /api/v3/secrets/batch/raw" +openapi: "DELETE /api/v4/secrets/batch" --- - diff --git a/docs/api-reference/endpoints/secrets/delete.mdx b/docs/api-reference/endpoints/secrets/delete.mdx index ef3abc722..f71a851e8 100644 --- a/docs/api-reference/endpoints/secrets/delete.mdx +++ b/docs/api-reference/endpoints/secrets/delete.mdx @@ -1,5 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v3/secrets/raw/{secretName}" +openapi: "DELETE /api/v4/secrets/{secretName}" --- - diff --git a/docs/api-reference/endpoints/secrets/list.mdx b/docs/api-reference/endpoints/secrets/list.mdx index 4808f6690..6a1f38d68 100644 --- a/docs/api-reference/endpoints/secrets/list.mdx +++ b/docs/api-reference/endpoints/secrets/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v3/secrets/raw" +openapi: "GET /api/v4/secrets" --- diff --git a/docs/api-reference/endpoints/secrets/read.mdx b/docs/api-reference/endpoints/secrets/read.mdx index 6af308e0f..10e725ba5 100644 --- a/docs/api-reference/endpoints/secrets/read.mdx +++ b/docs/api-reference/endpoints/secrets/read.mdx @@ -1,5 +1,4 @@ --- title: "Retrieve" -openapi: "GET /api/v3/secrets/raw/{secretName}" +openapi: "GET /api/v4/secrets/{secretName}" --- - diff --git a/docs/api-reference/endpoints/secrets/update-many.mdx b/docs/api-reference/endpoints/secrets/update-many.mdx index 7586d91bc..9aca17148 100644 --- a/docs/api-reference/endpoints/secrets/update-many.mdx +++ b/docs/api-reference/endpoints/secrets/update-many.mdx @@ -1,5 +1,4 @@ --- title: "Bulk Update" -openapi: "PATCH /api/v3/secrets/batch/raw" +openapi: "PATCH /api/v4/secrets/batch" --- - diff --git a/docs/api-reference/endpoints/secrets/update.mdx b/docs/api-reference/endpoints/secrets/update.mdx index ce68c492e..435f3e0c4 100644 --- a/docs/api-reference/endpoints/secrets/update.mdx +++ b/docs/api-reference/endpoints/secrets/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v3/secrets/raw/{secretName}" +openapi: "PATCH /api/v4/secrets/{secretName}" --- diff --git a/docs/docs.json b/docs/docs.json index 285e11a60..8b64210a0 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1009,28 +1009,55 @@ "api-reference/endpoints/organizations/delete-membership", "api-reference/endpoints/organizations/bulk-delete-memberships", "api-reference/endpoints/organizations/list-identity-memberships", - "api-reference/endpoints/organizations/workspaces" + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/organizations/projects" + ] + } ] }, { "group": "Projects", "pages": [ - "api-reference/endpoints/workspaces/get-workspace-by-slug", - "api-reference/endpoints/workspaces/create-workspace", - "api-reference/endpoints/workspaces/delete-workspace", - "api-reference/endpoints/workspaces/get-workspace", - "api-reference/endpoints/workspaces/update-workspace", - "api-reference/endpoints/workspaces/secret-snapshots" + "api-reference/endpoints/projects/get-project-by-slug", + "api-reference/endpoints/projects/create-project", + "api-reference/endpoints/projects/delete-project", + "api-reference/endpoints/projects/get-project", + "api-reference/endpoints/projects/list-projects", + "api-reference/endpoints/projects/update-project", + "api-reference/endpoints/projects/secret-snapshots", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/projects/get-project-by-slug", + "api-reference/endpoints/deprecated/projects/create-project", + "api-reference/endpoints/deprecated/projects/delete-project", + "api-reference/endpoints/deprecated/projects/get-project", + "api-reference/endpoints/deprecated/projects/update-project", + "api-reference/endpoints/deprecated/projects/secret-snapshots" + ] + } ] }, { "group": "Project Users", "pages": [ - "api-reference/endpoints/project-users/invite-member-to-workspace", - "api-reference/endpoints/project-users/remove-member-from-workspace", + "api-reference/endpoints/project-users/invite-member-to-project", + "api-reference/endpoints/project-users/remove-member-from-project", "api-reference/endpoints/project-users/memberships", "api-reference/endpoints/project-users/get-by-username", - "api-reference/endpoints/project-users/update-membership" + "api-reference/endpoints/project-users/update-membership", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/project-users/invite-member-to-project", + "api-reference/endpoints/deprecated/project-users/remove-member-from-project", + "api-reference/endpoints/deprecated/project-users/memberships", + "api-reference/endpoints/deprecated/project-users/get-by-username", + "api-reference/endpoints/deprecated/project-users/update-membership" + ] + } ] }, { @@ -1040,7 +1067,17 @@ "api-reference/endpoints/project-groups/delete", "api-reference/endpoints/project-groups/get-by-id", "api-reference/endpoints/project-groups/list", - "api-reference/endpoints/project-groups/update" + "api-reference/endpoints/project-groups/update", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/project-groups/create", + "api-reference/endpoints/deprecated/project-groups/delete", + "api-reference/endpoints/deprecated/project-groups/get-by-id", + "api-reference/endpoints/deprecated/project-groups/list", + "api-reference/endpoints/deprecated/project-groups/update" + ] + } ] }, { @@ -1050,7 +1087,17 @@ "api-reference/endpoints/project-identities/list-identity-memberships", "api-reference/endpoints/project-identities/get-by-id", "api-reference/endpoints/project-identities/update-identity-membership", - "api-reference/endpoints/project-identities/delete-identity-membership" + "api-reference/endpoints/project-identities/delete-identity-membership", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/project-identities/add-identity-membership", + "api-reference/endpoints/deprecated/project-identities/list-identity-memberships", + "api-reference/endpoints/deprecated/project-identities/get-by-id", + "api-reference/endpoints/deprecated/project-identities/update-identity-membership", + "api-reference/endpoints/deprecated/project-identities/delete-identity-membership" + ] + } ] }, { @@ -1060,7 +1107,17 @@ "api-reference/endpoints/project-roles/update", "api-reference/endpoints/project-roles/delete", "api-reference/endpoints/project-roles/get-by-slug", - "api-reference/endpoints/project-roles/list" + "api-reference/endpoints/project-roles/list", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/project-roles/create", + "api-reference/endpoints/deprecated/project-roles/update", + "api-reference/endpoints/deprecated/project-roles/delete", + "api-reference/endpoints/deprecated/project-roles/get-by-slug", + "api-reference/endpoints/deprecated/project-roles/list" + ] + } ] }, { @@ -1078,7 +1135,15 @@ "pages": [ "api-reference/endpoints/environments/create", "api-reference/endpoints/environments/update", - "api-reference/endpoints/environments/delete" + "api-reference/endpoints/environments/delete", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/environments/create", + "api-reference/endpoints/deprecated/environments/update", + "api-reference/endpoints/deprecated/environments/delete" + ] + } ] }, { @@ -1088,7 +1153,17 @@ "api-reference/endpoints/folders/get-by-id", "api-reference/endpoints/folders/create", "api-reference/endpoints/folders/update", - "api-reference/endpoints/folders/delete" + "api-reference/endpoints/folders/delete", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/folders/list", + "api-reference/endpoints/deprecated/folders/get-by-id", + "api-reference/endpoints/deprecated/folders/create", + "api-reference/endpoints/deprecated/folders/update", + "api-reference/endpoints/deprecated/folders/delete" + ] + } ] }, { @@ -1099,7 +1174,18 @@ "api-reference/endpoints/secret-tags/get-by-slug", "api-reference/endpoints/secret-tags/create", "api-reference/endpoints/secret-tags/update", - "api-reference/endpoints/secret-tags/delete" + "api-reference/endpoints/secret-tags/delete", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/secret-tags/list", + "api-reference/endpoints/deprecated/secret-tags/get-by-id", + "api-reference/endpoints/deprecated/secret-tags/get-by-slug", + "api-reference/endpoints/deprecated/secret-tags/create", + "api-reference/endpoints/deprecated/secret-tags/update", + "api-reference/endpoints/deprecated/secret-tags/delete" + ] + } ] }, { @@ -1113,8 +1199,21 @@ "api-reference/endpoints/secrets/create-many", "api-reference/endpoints/secrets/update-many", "api-reference/endpoints/secrets/delete-many", - "api-reference/endpoints/secrets/attach-tags", - "api-reference/endpoints/secrets/detach-tags" + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/secrets/list", + "api-reference/endpoints/deprecated/secrets/create", + "api-reference/endpoints/deprecated/secrets/read", + "api-reference/endpoints/deprecated/secrets/update", + "api-reference/endpoints/deprecated/secrets/delete", + "api-reference/endpoints/deprecated/secrets/create-many", + "api-reference/endpoints/deprecated/secrets/update-many", + "api-reference/endpoints/deprecated/secrets/delete-many", + "api-reference/endpoints/deprecated/secrets/attach-tags", + "api-reference/endpoints/deprecated/secrets/detach-tags" + ] + } ] }, { @@ -1144,7 +1243,16 @@ "api-reference/endpoints/secret-imports/list", "api-reference/endpoints/secret-imports/create", "api-reference/endpoints/secret-imports/update", - "api-reference/endpoints/secret-imports/delete" + "api-reference/endpoints/secret-imports/delete", + { + "group": "Legacy", + "pages": [ + "api-reference/endpoints/deprecated/secret-imports/list", + "api-reference/endpoints/deprecated/secret-imports/create", + "api-reference/endpoints/deprecated/secret-imports/update", + "api-reference/endpoints/deprecated/secret-imports/delete" + ] + } ] }, { diff --git a/docs/documentation/platform/audit-log-streams/audit-log-streams.mdx b/docs/documentation/platform/audit-log-streams/audit-log-streams.mdx index 50fa75e92..ad030ec26 100644 --- a/docs/documentation/platform/audit-log-streams/audit-log-streams.mdx +++ b/docs/documentation/platform/audit-log-streams/audit-log-streams.mdx @@ -45,6 +45,116 @@ Infisical Audit Log Streaming enables you to transmit your organization's audit ## Example Providers + + Infisical offers a dedicated **Azure** provider to stream your audit logs, enabling seamless integration with services like Microsoft Sentinel. + + + After setting up all Azure resources, it may take 10-20 minutes for logs to begin streaming. + + + + + Navigate to [Data Collection Endpoints](https://portal.azure.com/#view/HubsExtension/BrowseResource.ReactView/resourceType/microsoft.insights%2Fdatacollectionendpoints) and click **Create**. + + ![azure create dce](/images/platform/audit-log-streams/azure-create-dce.png) + + Configure your Data Collection Endpoint by providing an **Endpoint Name**, **Subscription**, and a **Resource group**. Then click **Review + Create**. + + ![azure configure dce](/images/platform/audit-log-streams/azure-configure-dce.png) + + After creation, it may take a few minutes for the Data Collection Endpoint to appear. Once visible, click on it and copy the **Logs Ingestion** URL. You will need this URL in later steps. + + ![azure dce url](/images/platform/audit-log-streams/azure-dce-url.png) + + + + If you already have a Log Analytics Workspace, you may skip this step. + + + Navigate to [Log Analytics Workspaces](https://portal.azure.com/#browse/Microsoft.OperationalInsights%2Fworkspaces) and click **Create**. + + ![azure create law](/images/platform/audit-log-streams/azure-create-law.png) + + Configure your Log Analytics Workspace by providing a **Subscription**, **Resource group**, and a **Name**. Then click **Review + Create**. + + ![azure configure law](/images/platform/audit-log-streams/azure-configure-law.png) + + Once the workspace is deployed, click **Go to resource** to access it. + + ![azure go to resource](/images/platform/audit-log-streams/azure-go-to-resource.png) + + + Within your Log Analytics Workspace, navigate to **Tables** and click **Create**. Select **New custom log (DCR-based)** from the dropdown. + + ![azure new table](/images/platform/audit-log-streams/azure-new-table.png) + + Configure the Custom Log Table: Provide a **Table name** (e.g., `InfisicalLogs`), select the **Data collection endpoint** created in Step 1, and create a new **Data collection rule** as illustrated in the image below. Then, click **Next**. + + ![azure configure table](/images/platform/audit-log-streams/azure-configure-table.png) + + On the **Schema and transformation** page, you'll be prompted to upload a **Log Sample**. Create a `.json` file with the following content and upload it: + + ```json + { + "id": "00000000-0000-0000-0000-000000000000", + "actor": "user", + "actorMetadata": { + "email": "user@example.com", + "userId": "00000000-0000-0000-0000-000000000000", + "username": "user@example.com" + }, + "ipAddress": "0.0.0.0", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36", + "userAgentType": "web", + "eventType": "get-secrets", + "eventMetadata": {}, + "projectName": "MyProject", + "orgId": "00000000-0000-0000-0000-000000000000", + "projectId": "00000000-0000-0000-0000-000000000000", + "TimeGenerated": "2025-01-01T00:00:00.000Z" + } + ``` + + Optionally, you can add **Transformations** to further destructure the data. For example, to extract actor email and userId: + + ``` + source + | extend + ActorEmail = tostring(actorMetadata.email), + ActorUserId = tostring(actorMetadata.userId) + ``` + + On the final step, click **Create**. + + + It may take a few minutes for your Custom Log Table to be created and appear under Tables. + + + + After creating your Data Collection Rule, you'll need its **Immutable ID**. + + Navigate to [Data collection rules](https://portal.azure.com/#view/HubsExtension/BrowseResource.ReactView/resourceType/microsoft.insights%2Fdatacollectionrules). Click on your newly created DCR and copy its **Immutable ID** for the next step. + + ![azure dcr](/images/platform/audit-log-streams/azure-dcr.png) + + + In Infisical, create a new audit log stream and select the **Azure** provider. Input the following details: + + - **Tenant ID**: Your Tenant ID + - **Client ID**: The Client ID of an App Registration + - **Client Secret**: The Client Secret of an App Registration + - **Data Collection Endpoint URL**: Obtained from Step 1 + - **Data Collection Rule Immutable ID**: Obtained from Step 4 + - **Custom Log Table Name**: Defined in Step 3 + + ![azure create als](/images/platform/audit-log-streams/azure-create-als.png) + + + The App Registration used for authentication must have the **Monitoring Metrics Publisher** role assigned on the **Data Collection Rule** created in Step 3. [See Microsoft Guide](https://learn.microsoft.com/en-us/azure/azure-monitor/logs/tutorial-logs-ingestion-portal#assign-permissions-to-the-dcr). + + + + You can stream to Better Stack using a **Custom** log stream. diff --git a/docs/images/platform/audit-log-streams/azure-configure-dce.png b/docs/images/platform/audit-log-streams/azure-configure-dce.png new file mode 100644 index 000000000..b0b32f0b2 Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-configure-dce.png differ diff --git a/docs/images/platform/audit-log-streams/azure-configure-law.png b/docs/images/platform/audit-log-streams/azure-configure-law.png new file mode 100644 index 000000000..11ec8d86f Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-configure-law.png differ diff --git a/docs/images/platform/audit-log-streams/azure-configure-table.png b/docs/images/platform/audit-log-streams/azure-configure-table.png new file mode 100644 index 000000000..7dba237b9 Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-configure-table.png differ diff --git a/docs/images/platform/audit-log-streams/azure-create-als.png b/docs/images/platform/audit-log-streams/azure-create-als.png new file mode 100644 index 000000000..bdfb2f8d6 Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-create-als.png differ diff --git a/docs/images/platform/audit-log-streams/azure-create-dce.png b/docs/images/platform/audit-log-streams/azure-create-dce.png new file mode 100644 index 000000000..00a546c30 Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-create-dce.png differ diff --git a/docs/images/platform/audit-log-streams/azure-create-law.png b/docs/images/platform/audit-log-streams/azure-create-law.png new file mode 100644 index 000000000..1150f64ff Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-create-law.png differ diff --git a/docs/images/platform/audit-log-streams/azure-dce-url.png b/docs/images/platform/audit-log-streams/azure-dce-url.png new file mode 100644 index 000000000..d8c1dc96d Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-dce-url.png differ diff --git a/docs/images/platform/audit-log-streams/azure-dcr.png b/docs/images/platform/audit-log-streams/azure-dcr.png new file mode 100644 index 000000000..441808947 Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-dcr.png differ diff --git a/docs/images/platform/audit-log-streams/azure-go-to-resource.png b/docs/images/platform/audit-log-streams/azure-go-to-resource.png new file mode 100644 index 000000000..ef197517d Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-go-to-resource.png differ diff --git a/docs/images/platform/audit-log-streams/azure-new-table.png b/docs/images/platform/audit-log-streams/azure-new-table.png new file mode 100644 index 000000000..829af3e53 Binary files /dev/null and b/docs/images/platform/audit-log-streams/azure-new-table.png differ diff --git a/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx index 76dd24cf7..848da4055 100644 --- a/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-dynamic-secret-crd.mdx @@ -223,7 +223,9 @@ spec: spec: dynamicSecret: secretName: - projectId: + # Use either projectId OR projectSlug, not both + projectId: # Either projectId or projectSlug is required + # projectSlug: environmentSlug: secretsPath: ``` @@ -238,8 +240,21 @@ spec: The project ID of where the dynamic secret is stored in Infisical. + + + Please note that you can only use either `projectId` or `projectSlug` in the `dynamicSecret` field. + + + The project slug of where the dynamic secret is stored in Infisical. + + + Please note that you can only use either `projectId` or `projectSlug` in the `dynamicSecret` field. + + + + {" "} diff --git a/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx index d5a9c1ef4..0affe7841 100644 --- a/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-push-secret-crd.mdx @@ -44,7 +44,8 @@ Before applying the InfisicalPushSecret CRD, you need to create a Kubernetes sec deletionPolicy: Delete # If set to delete, the secret(s) inside Infisical managed by the operator, will be deleted if the InfisicalPushSecret CRD is deleted. destination: - projectId: + projectId: # Either projectId or projectSlug is required + projectSlug: environmentSlug: secretsPath: @@ -203,6 +204,18 @@ After applying the InfisicalPushSecret CRD, you should notice that the secrets y The project ID where you want to create the secrets in Infisical. + + + Please note that you can only use either `projectId` or `projectSlug` in the `destination` field. + + + + + The project slug where you want to create the secrets in Infisical. + + + Please note that you can only use either `projectId` or `projectSlug` in the `destination` field. + diff --git a/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx b/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx index d0e403b79..d72d58957 100644 --- a/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx +++ b/docs/integrations/platforms/kubernetes/infisical-secret-crd.mdx @@ -142,7 +142,10 @@ spec: authentication: universalAuth: secretsScope: + # either projectSlug or projectId is required projectSlug: # <-- project slug + projectId: # <-- project id + envSlug: # "dev", "staging", "prod", etc.. secretsPath: "" # Root is "/" credentialsRef: @@ -496,9 +499,11 @@ spec: Make sure to also populate the `secretsScope` field with the project slug - _`projectSlug`_, environment slug _`envSlug`_, and secrets path + _`projectSlug`_, or project ID _`projectId`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below. + + Please note that you can only use either `projectSlug` or `projectId` in the `secretsScope` field. ## Example @@ -545,9 +550,11 @@ spec: Make sure to also populate the `secretsScope` field with the project slug - _`projectSlug`_, environment slug _`envSlug`_, and secrets path + _`projectSlug`_, or project ID _`projectId`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below. + + Please note that you can only use either `projectSlug` or `projectId` in the `secretsScope` field. ## Example @@ -588,9 +595,11 @@ spec: Make sure to also populate the `secretsScope` field with the project slug - _`projectSlug`_, environment slug _`envSlug`_, and secrets path + _`projectSlug`_, or project ID _`projectId`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below. + + Please note that you can only use either `projectSlug` or `projectId` in the `secretsScope` field. ## Example @@ -631,9 +640,11 @@ spec: Make sure to also populate the `secretsScope` field with the project slug - _`projectSlug`_, environment slug _`envSlug`_, and secrets path + _`projectSlug`_, or project ID _`projectId`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below. + + Please note that you can only use either `projectSlug` or `projectId` in the `secretsScope` field. ## Example @@ -675,9 +686,11 @@ spec: Make sure to also populate the `secretsScope` field with the project slug - _`projectSlug`_, environment slug _`envSlug`_, and secrets path + _`projectSlug`_, or project ID _`projectId`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below. + + Please note that you can only use either `projectSlug` or `projectId` in the `secretsScope` field. ## Example @@ -730,9 +743,11 @@ spec: Make sure to also populate the `secretsScope` field with the project slug - _`projectSlug`_, environment slug _`envSlug`_, and secrets path + _`projectSlug`_, or project ID _`projectId`_, environment slug _`envSlug`_, and secrets path _`secretsPath`_ that you want to fetch secrets from. Please see the example below. + + Please note that you can only use either `projectSlug` or `projectId` in the `secretsScope` field. ## Example diff --git a/docs/internals/permissions/organization-permissions.mdx b/docs/internals/permissions/organization-permissions.mdx index 5f5fc962f..d20ea7def 100644 --- a/docs/internals/permissions/organization-permissions.mdx +++ b/docs/internals/permissions/organization-permissions.mdx @@ -9,7 +9,7 @@ Infisical's organization permissions system follows a role-based access control Each permission consists of: -- **Subject**: The resource the permission applies to (e.g., workspaces, members, billing) +- **Subject**: The resource the permission applies to (e.g., project, members, billing) - **Action**: The operation that can be performed (e.g., read, create, edit, delete) Some organization-level resources—specifically `app-connections`—support conditional permissions and permission inversion for more granular access control. @@ -18,13 +18,13 @@ Some organization-level resources—specifically `app-connections`—support con Below is a comprehensive list of all available organization-level subjects and their supported actions, organized by functional area. -### Workspace Management +### Project Management -#### Subject: `workspace` +#### Subject: `project` (formerly workspace) -| Action | Description | -| -------- | --------------------- | -| `create` | Create new workspaces | +| Action | Description | +| -------- | ------------------ | +| `create` | Create new project | ### Role Management diff --git a/docs/internals/permissions/project-permissions.mdx b/docs/internals/permissions/project-permissions.mdx index dbc2e5271..3a4dd11e6 100644 --- a/docs/internals/permissions/project-permissions.mdx +++ b/docs/internals/permissions/project-permissions.mdx @@ -86,7 +86,7 @@ Below is a comprehensive list of all available project-level subjects and their | `edit` | Modify existing tags | | `delete` | Remove tags from the project | -#### Subject: `workspace` +#### Subject: `project` | Action | Description | | -------- | ------------------------- | diff --git a/docs/self-hosting/guides/upgrading-infisical.mdx b/docs/self-hosting/guides/upgrading-infisical.mdx index 60c6edbff..cae8193bf 100644 --- a/docs/self-hosting/guides/upgrading-infisical.mdx +++ b/docs/self-hosting/guides/upgrading-infisical.mdx @@ -54,4 +54,62 @@ Now, migrations run automatically during boot-up. This improvement streamlines t - Once the migration is complete, all instances will operate with the updated schema. 5. **Verify the Upgrade:** - - Review the logs for any migration errors or warnings. + - Review the logs for any migration errors or warnings. + - Test basic functionality to ensure the upgrade was successful. + +## Troubleshooting + +### UI Caching Issues After Upgrade + +After upgrading your Infisical instance, you may encounter UI-related issues such as: +- Strange loading behavior +- Components not rendering correctly +- Unexpected errors in the browser console +- Features appearing broken or unresponsive + +These issues are often caused by browser caching of the previous version's static assets. + +**Solution:** +1. **Try a private/incognito browser window first** - This is the quickest way to test if the issue is cache-related. +2. **Clear your browser cache** if the private window works correctly: + - **Chrome/Edge:** Press `Ctrl+Shift+Delete` (Windows/Linux) or `Cmd+Shift+Delete` (Mac) + - **Firefox:** Press `Ctrl+Shift+Delete` (Windows/Linux) or `Cmd+Shift+Delete` (Mac) + - **Safari:** Press `Cmd+Option+E` or go to Develop menu > Empty Caches +3. **Hard refresh the page** by pressing `Ctrl+F5` (Windows/Linux) or `Cmd+Shift+R` (Mac) + + + Caching issues are temporary and typically resolve themselves as the cache expires, but manually clearing the cache provides immediate resolution. + + +## Downgrade Considerations + +While we recommend staying up-to-date with the latest version, there may be scenarios where you need to downgrade your Infisical instance. + + + **Database Compatibility:** Downgrading can be complex due to database schema changes. Always ensure you have proper backups before attempting any version changes. + + +### Safe Downgrade Process + +1. **Prepare Database Snapshot:** + - Create a database snapshot/backup **before** upgrading to the target version + - Ensure the snapshot is from a version compatible with your desired downgrade target + +2. **Stop Infisical Services:** + - Gracefully shut down all Infisical instances to prevent data corruption + +3. **Restore Database:** + - Restore your database from the pre-upgrade snapshot + - **Critical:** Do not attempt to downgrade with a database that has run migrations from a newer version + +4. **Deploy Previous Version:** + - Deploy the previous Infisical version + - Verify that the version matches the database schema in your snapshot + +5. **Verify Functionality:** + - Test critical functionality to ensure the downgrade was successful + - Monitor logs for any compatibility issues + + + The safest approach for downgrades is to restore to a known good state (both application and database) rather than attempting to reverse individual migrations. + diff --git a/frontend/src/components/navigation/NavHeader.tsx b/frontend/src/components/navigation/NavHeader.tsx index 1283c02d1..b16015680 100644 --- a/frontend/src/components/navigation/NavHeader.tsx +++ b/frontend/src/components/navigation/NavHeader.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Link, useParams } from "@tanstack/react-router"; import { twMerge } from "tailwind-merge"; -import { useOrganization, useWorkspace } from "@app/context"; +import { useOrganization, useProject } from "@app/context"; import { useToggle } from "@app/hooks"; import { createNotification } from "../notifications"; @@ -51,7 +51,7 @@ export default function NavHeader({ isProtectedBranch = false, protectionPolicyName }: Props): JSX.Element { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { currentOrg } = useOrganization(); const [isCopied, { timedToggle: toggleIsCopied }] = useToggle(false); @@ -79,7 +79,7 @@ export default function NavHeader({ <>
- {currentWorkspace?.name} + {currentProject?.name}
)} @@ -93,7 +93,7 @@ export default function NavHeader({ {pageName === "Secrets" ? ( {pageName} @@ -129,7 +129,7 @@ export default function NavHeader({ {userAvailableEnvs?.find(({ slug }) => slug === currentEnv)?.name} @@ -192,7 +192,7 @@ export default function NavHeader({ ({ ...query, secretPath: newSecretPath })} diff --git a/frontend/src/components/permissions/AccessTree/hooks/index.ts b/frontend/src/components/permissions/AccessTree/hooks/index.ts index 717bdaf3a..b02e6a9d6 100644 --- a/frontend/src/components/permissions/AccessTree/hooks/index.ts +++ b/frontend/src/components/permissions/AccessTree/hooks/index.ts @@ -3,7 +3,7 @@ import { useFormContext, useWatch } from "react-hook-form"; import { MongoAbility, MongoQuery } from "@casl/ability"; import { Edge, Node, useEdgesState, useNodesState } from "@xyflow/react"; -import { ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject } from "@app/context"; import { ProjectPermissionSet } from "@app/context/ProjectPermissionContext"; import { useListProjectEnvironmentsFolders } from "@app/hooks/api/secretFolders/queries"; import { TSecretFolderWithPath } from "@app/hooks/api/secretFolders/types"; @@ -36,15 +36,15 @@ export const useAccessTree = ( searchPath: string, subject: ProjectPermissionSub ) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { secretName, setSecretName, setViewMode, viewMode } = useAccessTreeContext(); const { control } = useFormContext(); const metadata = useWatch({ control, name: "metadata" }); const [nodes, setNodes] = useNodesState([]); const [edges, setEdges] = useEdgesState([]); - const [environment, setEnvironment] = useState(currentWorkspace.environments[0]?.slug ?? ""); + const [environment, setEnvironment] = useState(currentProject.environments[0]?.slug ?? ""); const { data: environmentsFolders, isPending } = useListProjectEnvironmentsFolders( - currentWorkspace.id + currentProject.id ); const [levelFolderMap, setLevelFolderMap] = useState({}); @@ -279,7 +279,7 @@ export const useAccessTree = ( environment, setEnvironment, isLoading: isPending, - environments: currentWorkspace.environments, + environments: currentProject.environments, secretName, setSecretName, viewMode, diff --git a/frontend/src/components/project/ProjectOverviewChangeSection.tsx b/frontend/src/components/project/ProjectOverviewChangeSection.tsx index 0f88ec2e9..852253bb3 100644 --- a/frontend/src/components/project/ProjectOverviewChangeSection.tsx +++ b/frontend/src/components/project/ProjectOverviewChangeSection.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, FormControl, Input, TextArea } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useUpdateProject } from "@app/hooks/api"; const baseFormSchema = z.object({ @@ -37,35 +37,35 @@ type Props = { }; export const ProjectOverviewChangeSection = ({ showSlugField = false }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync, isPending } = useUpdateProject(); const { handleSubmit, control, reset, watch } = useForm({ resolver: zodResolver(showSlugField ? formSchemaWithSlug : baseFormSchema) }); - const currentSlug = showSlugField ? watch("slug") : currentWorkspace?.slug; + const currentSlug = showSlugField ? watch("slug") : currentProject?.slug; useEffect(() => { - if (currentWorkspace) { + if (currentProject) { reset({ - name: currentWorkspace.name, - description: currentWorkspace.description ?? "", - ...(showSlugField && { slug: currentWorkspace.slug }) + name: currentProject.name, + description: currentProject.description ?? "", + ...(showSlugField && { slug: currentProject.slug }) }); } - }, [currentWorkspace, showSlugField]); + }, [currentProject, showSlugField]); const onFormSubmit = async (data: BaseFormData | FormDataWithSlug) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await mutateAsync({ - projectID: currentWorkspace.id, + projectId: currentProject.id, newProjectName: data.name, newProjectDescription: data.description, ...(showSlugField && "slug" in data && { - newSlug: data.slug !== currentWorkspace.slug ? data.slug : undefined + newSlug: data.slug !== currentProject.slug ? data.slug : undefined }) }); @@ -105,7 +105,7 @@ export const ProjectOverviewChangeSection = ({ showSlugField = false }: Props) = variant="outline_bg" size="sm" onClick={() => { - navigator.clipboard.writeText(currentWorkspace?.id || ""); + navigator.clipboard.writeText(currentProject?.id || ""); createNotification({ text: "Copied project ID to clipboard", type: "success" diff --git a/frontend/src/components/projects/NewProjectModal.tsx b/frontend/src/components/projects/NewProjectModal.tsx index 1bbe9f6f1..dcb11d873 100644 --- a/frontend/src/components/projects/NewProjectModal.tsx +++ b/frontend/src/components/projects/NewProjectModal.tsx @@ -34,10 +34,10 @@ import { useUser } from "@app/context"; import { getProjectHomePage, getProjectLottieIcon } from "@app/helpers/project"; -import { useCreateWorkspace, useGetExternalKmsList, useGetUserWorkspaces } from "@app/hooks/api"; +import { useCreateWorkspace, useGetExternalKmsList, useGetUserProjects } from "@app/hooks/api"; import { INTERNAL_KMS_KEY_ID } from "@app/hooks/api/kms/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { InfisicalProjectTemplate, useListProjectTemplates } from "@app/hooks/api/projectTemplates"; -import { ProjectType } from "@app/hooks/api/workspace/types"; const formSchema = z.object({ name: z.string().trim().min(1, "Required").max(64, "Too long, maximum length is 64 characters"), @@ -89,7 +89,7 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => { const { permission } = useOrgPermission(); const { user } = useUser(); const createWs = useCreateWorkspace(); - const { refetch: refetchWorkspaces } = useGetUserWorkspaces(); + const { refetch: refetchWorkspaces } = useGetUserProjects(); const { subscription } = useSubscription(); const canReadProjectTemplates = permission.can( diff --git a/frontend/src/components/projects/RequestProjectAccessModal.tsx b/frontend/src/components/projects/RequestProjectAccessModal.tsx index a0c5de76f..6d31bf8e6 100644 --- a/frontend/src/components/projects/RequestProjectAccessModal.tsx +++ b/frontend/src/components/projects/RequestProjectAccessModal.tsx @@ -3,7 +3,7 @@ import { useForm } from "react-hook-form"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalClose, ModalContent } from "@app/components/v2"; import { useRequestProjectAccess } from "@app/hooks/api"; -import { Workspace } from "@app/hooks/api/workspace/types"; +import { Project } from "@app/hooks/api/projects/types"; type ContentProps = { projectId: string; @@ -57,7 +57,7 @@ const Content = ({ projectId, onComplete }: ContentProps) => { type RequestProjectAccessModalProps = { isOpen: boolean; onOpenChange: (isOpen: boolean) => void; - project?: Workspace; + project?: Project; onComplete?: () => void; }; diff --git a/frontend/src/components/secret-rotations-v2/CreateSecretRotationV2Modal.tsx b/frontend/src/components/secret-rotations-v2/CreateSecretRotationV2Modal.tsx index 89ced26b7..41f378b94 100644 --- a/frontend/src/components/secret-rotations-v2/CreateSecretRotationV2Modal.tsx +++ b/frontend/src/components/secret-rotations-v2/CreateSecretRotationV2Modal.tsx @@ -8,13 +8,13 @@ import { TSecretRotationV2Form } from "@app/components/secret-rotations-v2/forms import { SecretRotationV2ModalHeader } from "@app/components/secret-rotations-v2/SecretRotationV2ModalHeader"; import { SecretRotationV2Select } from "@app/components/secret-rotations-v2/SecretRotationV2Select"; import { Modal, ModalContent } from "@app/components/v2"; +import { ProjectEnv } from "@app/hooks/api/projects/types"; import { SecretRotation, TSecretRotationV2 } from "@app/hooks/api/secretRotationsV2"; -import { WorkspaceEnv } from "@app/hooks/api/workspace/types"; type SharedProps = { secretPath: string; environment?: string; - environments?: WorkspaceEnv[]; + environments?: ProjectEnv[]; }; type Props = { diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConfigurationFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConfigurationFields.tsx index 1906b743d..e518752c4 100644 --- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConfigurationFields.tsx +++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConfigurationFields.tsx @@ -9,14 +9,14 @@ import { IS_ROTATION_DUAL_CREDENTIALS, SECRET_ROTATION_MAP } from "@app/helpers/secretRotationsV2"; -import { WorkspaceEnv } from "@app/hooks/api/workspace/types"; +import { ProjectEnv } from "@app/hooks/api/projects/types"; import { TSecretRotationV2Form } from "./schemas"; import { SecretRotationV2ConnectionField } from "./SecretRotationV2ConnectionField"; type Props = { isUpdate: boolean; - environments?: WorkspaceEnv[]; + environments?: ProjectEnv[]; }; export const SecretRotationV2ConfigurationFields = ({ isUpdate, environments }: Props) => { diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConnectionField.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConnectionField.tsx index 407a473d1..c2064071f 100644 --- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConnectionField.tsx +++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ConnectionField.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { AppConnectionOption } from "@app/components/app-connections"; import { FilterableSelect, FormControl } from "@app/components/v2"; -import { ProjectPermissionSub, useProjectPermission, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject, useProjectPermission } from "@app/context"; import { ProjectPermissionAppConnectionActions } from "@app/context/ProjectPermissionContext/types"; import { APP_CONNECTION_MAP } from "@app/helpers/appConnections"; import { SECRET_ROTATION_CONNECTION_MAP } from "@app/helpers/secretRotationsV2"; @@ -29,11 +29,11 @@ export const SecretRotationV2ConnectionField = ({ onChange: callback, isUpdate } const rotationType = watch("type"); const app = SECRET_ROTATION_CONNECTION_MAP[rotationType]; - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: availableConnections, isPending } = useListAvailableAppConnections( app, - currentWorkspace.id + currentProject.id ); const connectionName = APP_CONNECTION_MAP[app].name; @@ -117,8 +117,8 @@ export const SecretRotationV2ConnectionField = ({ onChange: callback, isUpdate } localStorage.removeItem("secretRotationFormData"); handlePopUpToggle("addConnection", isOpen); }} - projectType={currentWorkspace.type} - projectId={currentWorkspace.id} + projectType={currentProject.type} + projectId={currentProject.id} app={app} onComplete={(connection) => { if (connection) { diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx index 62efaa8d2..87869e925 100644 --- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx +++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2Form.tsx @@ -11,8 +11,9 @@ import { SecretRotationV2ParametersFields } from "@app/components/secret-rotatio import { SecretRotationV2ReviewFields } from "@app/components/secret-rotations-v2/forms/SecretRotationV2ReviewFields"; import { SecretRotationV2SecretsMappingFields } from "@app/components/secret-rotations-v2/forms/SecretRotationV2SecretsMappingFields"; import { Button } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { IS_ROTATION_DUAL_CREDENTIALS, SECRET_ROTATION_MAP } from "@app/helpers/secretRotationsV2"; +import { ProjectEnv } from "@app/hooks/api/projects/types"; import { SecretRotation, TSecretRotationV2, @@ -22,7 +23,6 @@ import { useCreateSecretRotationV2, useUpdateSecretRotationV2 } from "@app/hooks/api/secretRotationsV2/mutations"; -import { WorkspaceEnv } from "@app/hooks/api/workspace/types"; import { SecretRotationV2FormSchema, TSecretRotationV2Form } from "./schemas"; @@ -32,7 +32,7 @@ type Props = { onCancel: () => void; secretPath: string; environment?: string; - environments?: WorkspaceEnv[]; + environments?: ProjectEnv[]; secretRotation?: TSecretRotationV2; initialFormData?: Partial; }; @@ -70,7 +70,7 @@ export const SecretRotationV2Form = ({ }: Props) => { const createSecretRotation = useCreateSecretRotationV2(); const updateSecretRotation = useUpdateSecretRotationV2(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { name: rotationType } = SECRET_ROTATION_MAP[type]; const [selectedTabIndex, setSelectedTabIndex] = useState(0); @@ -82,7 +82,7 @@ export const SecretRotationV2Form = ({ defaultValues: secretRotation ? { ...secretRotation, - environment: currentWorkspace?.environments.find((env) => env.slug === envSlug), + environment: currentProject?.environments.find((env) => env.slug === envSlug), secretPath } : { @@ -93,7 +93,7 @@ export const SecretRotationV2Form = ({ hours: 0, minutes: 0 }, - environment: currentWorkspace?.environments.find((env) => env.slug === envSlug), + environment: currentProject?.environments.find((env) => env.slug === envSlug), secretPath, ...((rotationOption?.template as object) ?? {}), // can't infer type since we don't know which specific type it is ...(initialFormData as object) @@ -118,7 +118,7 @@ export const SecretRotationV2Form = ({ connectionId: connection.id, environment: environment.slug, - projectId: currentWorkspace.id + projectId: currentProject.id }); try { const rotation = await mutation; diff --git a/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceConnectionField.tsx b/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceConnectionField.tsx index a58908da5..2e9e4a2a5 100644 --- a/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceConnectionField.tsx +++ b/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceConnectionField.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { AppConnectionOption } from "@app/components/app-connections"; import { FilterableSelect, FormControl } from "@app/components/v2"; -import { ProjectPermissionSub, useProjectPermission, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject, useProjectPermission } from "@app/context"; import { ProjectPermissionAppConnectionActions } from "@app/context/ProjectPermissionContext/types"; import { APP_CONNECTION_MAP } from "@app/helpers/appConnections"; import { SECRET_SCANNING_DATA_SOURCE_CONNECTION_MAP } from "@app/helpers/secretScanningV2"; @@ -32,11 +32,11 @@ export const SecretScanningDataSourceConnectionField = ({ const dataSourceType = watch("type"); const app = SECRET_SCANNING_DATA_SOURCE_CONNECTION_MAP[dataSourceType]; - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: availableConnections, isPending } = useListAvailableAppConnections( app, - currentWorkspace.id + currentProject.id ); const connectionName = APP_CONNECTION_MAP[app].name; @@ -119,8 +119,8 @@ export const SecretScanningDataSourceConnectionField = ({ localStorage.removeItem("secretScanningDataSourceFormData"); handlePopUpToggle("addConnection", isOpen); }} - projectType={currentWorkspace.type} - projectId={currentWorkspace.id} + projectType={currentProject.type} + projectId={currentProject.id} app={app} onComplete={(connection) => { if (connection) { diff --git a/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceForm.tsx b/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceForm.tsx index 49568dfec..515a67436 100644 --- a/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceForm.tsx +++ b/frontend/src/components/secret-scanning/forms/SecretScanningDataSourceForm.tsx @@ -6,7 +6,7 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { Button } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { SECRET_SCANNING_DATA_SOURCE_MAP } from "@app/helpers/secretScanningV2"; import { SecretScanningDataSource, @@ -46,7 +46,7 @@ export const SecretScanningDataSourceForm = ({ }: Props) => { const createDataSource = useCreateSecretScanningDataSource(); const updateDataSource = useUpdateSecretScanningDataSource(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { name: sourceType } = SECRET_SCANNING_DATA_SOURCE_MAP[type]; const [selectedTabIndex, setSelectedTabIndex] = useState(0); @@ -71,7 +71,7 @@ export const SecretScanningDataSourceForm = ({ : createDataSource.mutateAsync({ ...formData, connectionId: connection?.id, - projectId: currentWorkspace.id + projectId: currentProject.id }); try { const source = await mutation; diff --git a/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx b/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx index 082054ad2..4135a9926 100644 --- a/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx +++ b/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx @@ -8,7 +8,7 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Switch } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs"; import { SecretSync, @@ -47,7 +47,7 @@ export const CreateSecretSyncForm = ({ initialFormData }: Props) => { const createSecretSync = useCreateSecretSync(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { name: destinationName } = SECRET_SYNC_MAP[destination]; const [showConfirmation, setShowConfirmation] = useState(false); @@ -78,7 +78,7 @@ export const CreateSecretSyncForm = ({ ...formData, connectionId: connection.id, environment: environment.slug, - projectId: currentWorkspace.id + projectId: currentProject.id }); createNotification({ diff --git a/frontend/src/components/secret-syncs/forms/SecretSyncConnectionField.tsx b/frontend/src/components/secret-syncs/forms/SecretSyncConnectionField.tsx index 290f36206..62542a570 100644 --- a/frontend/src/components/secret-syncs/forms/SecretSyncConnectionField.tsx +++ b/frontend/src/components/secret-syncs/forms/SecretSyncConnectionField.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { AppConnectionOption } from "@app/components/app-connections"; import { FilterableSelect, FormControl } from "@app/components/v2"; -import { ProjectPermissionSub, useProjectPermission, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject, useProjectPermission } from "@app/context"; import { ProjectPermissionAppConnectionActions } from "@app/context/ProjectPermissionContext/types"; import { APP_CONNECTION_MAP } from "@app/helpers/appConnections"; import { SECRET_SYNC_CONNECTION_MAP } from "@app/helpers/secretSyncs"; @@ -28,11 +28,11 @@ export const SecretSyncConnectionField = ({ onChange: callback }: Props) => { const destination = watch("destination"); const app = SECRET_SYNC_CONNECTION_MAP[destination]; - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: availableConnections, isPending } = useListAvailableAppConnections( app, - currentWorkspace.id + currentProject.id ); const connectionName = APP_CONNECTION_MAP[app].name; @@ -101,8 +101,8 @@ export const SecretSyncConnectionField = ({ onChange: callback }: Props) => { localStorage.removeItem("secretSyncFormData"); handlePopUpToggle("addConnection", isOpen); }} - projectType={currentWorkspace.type} - projectId={currentWorkspace.id} + projectType={currentProject.type} + projectId={currentProject.id} app={app} onComplete={(connection) => { if (connection) { diff --git a/frontend/src/components/secret-syncs/forms/SecretSyncSourceFields.tsx b/frontend/src/components/secret-syncs/forms/SecretSyncSourceFields.tsx index 850ebbc80..127ac503c 100644 --- a/frontend/src/components/secret-syncs/forms/SecretSyncSourceFields.tsx +++ b/frontend/src/components/secret-syncs/forms/SecretSyncSourceFields.tsx @@ -4,7 +4,7 @@ import { subject } from "@casl/ability"; import { FilterableSelect, FormControl } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { ProjectPermissionSecretSyncActions, ProjectPermissionSub @@ -16,7 +16,7 @@ export const SecretSyncSourceFields = () => { const { control, watch, setError, clearErrors } = useFormContext(); const { permission } = useProjectPermission(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const selectedEnvironment = watch("environment"); const selectedSecretPath = watch("secretPath"); @@ -48,7 +48,7 @@ export const SecretSyncSourceFields = () => {

( @@ -56,7 +56,7 @@ export const SecretSyncSourceFields = () => { option?.name} getOptionValue={(option) => option?.id} diff --git a/frontend/src/components/secrets/SecretReferenceDetails/SecretReferenceDetails.tsx b/frontend/src/components/secrets/SecretReferenceDetails/SecretReferenceDetails.tsx index a9542c90c..ada741145 100644 --- a/frontend/src/components/secrets/SecretReferenceDetails/SecretReferenceDetails.tsx +++ b/frontend/src/components/secrets/SecretReferenceDetails/SecretReferenceDetails.tsx @@ -13,7 +13,7 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { FormControl, FormLabel, SecretInput, Spinner, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useGetSecretReferenceTree } from "@app/hooks/api"; import { ApiErrorTypes, TApiErrors, TSecretReferenceTraceNode } from "@app/hooks/api/types"; @@ -89,8 +89,8 @@ export const SecretReferenceNode = ({ }; export const SecretReferenceTree = ({ secretPath, environment, secretKey }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data, isPending, isError, error } = useGetSecretReferenceTree({ secretPath, diff --git a/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx b/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx index b1773b2e3..d48b7d95f 100644 --- a/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx +++ b/frontend/src/components/tags/CreateTagModal/CreateTagModal.tsx @@ -15,7 +15,7 @@ import { ModalContent, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateWsTag } from "@app/hooks/api"; import { slugSchema } from "@app/lib/schemas"; @@ -115,11 +115,10 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => { } }); - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { mutateAsync: createWsTag } = useCreateWsTag(); - const [showHexInput, setShowHexInput] = useState(false); const selectedTagColor = watch("color", secretTagsColors[0].hex); @@ -130,7 +129,7 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => { const onFormSubmit = async ({ slug, color }: FormData) => { try { await createWsTag({ - workspaceID: workspaceId, + projectId, tagColor: color, tagSlug: slug }); diff --git a/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx b/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx index ee2f196b1..ec09a93eb 100644 --- a/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx +++ b/frontend/src/components/v2/InfisicalSecretInput/InfisicalSecretInput.tsx @@ -3,7 +3,7 @@ import { faFolder, faKey, faLayerGroup } from "@fortawesome/free-solid-svg-icons import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Popover from "@radix-ui/react-popover"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useDebounce, useToggle } from "@app/hooks"; import { useGetProjectFolders, useGetProjectSecrets } from "@app/hooks/api"; @@ -76,8 +76,8 @@ export const InfisicalSecretInput = forwardRef( }, ref ) => { - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const [debouncedValue] = useDebounce(value, 100); @@ -101,7 +101,7 @@ export const InfisicalSecretInput = forwardRef( let predicate = suggestionSourceValue; if (isDeep) { const [envSlug, ...folderPaths] = suggestionSourceValue.split("."); - const isValidEnvSlug = currentWorkspace?.environments.find((e) => e.slug === envSlug); + const isValidEnvSlug = currentProject?.environments.find((e) => e.slug === envSlug); suggestionSourceEnv = isValidEnvSlug ? envSlug : undefined; suggestionSourceSecretPath = `/${folderPaths.slice(0, -1)?.join("/")}`; predicate = folderPaths[folderPaths.length - 1]; @@ -125,7 +125,7 @@ export const InfisicalSecretInput = forwardRef( viewSecretValue: false, environment: suggestionSource.environment || "", secretPath: suggestionSource.secretPath || "", - workspaceId, + projectId, options: { enabled: isPopupOpen } @@ -133,7 +133,7 @@ export const InfisicalSecretInput = forwardRef( const { data: folders } = useGetProjectFolders({ environment: suggestionSource.environment || "", path: suggestionSource.secretPath || "", - projectId: workspaceId, + projectId, options: { enabled: isPopupOpen } @@ -148,7 +148,7 @@ export const InfisicalSecretInput = forwardRef( if (!suggestionSource.isDeep) { // At first level only environments and secrets - (currentWorkspace?.environments || []).forEach(({ name, slug }) => { + (currentProject?.environments || []).forEach(({ name, slug }) => { if (name.toLowerCase().startsWith(predicate)) suggestionsArr.push({ label: name, @@ -176,7 +176,7 @@ export const InfisicalSecretInput = forwardRef( }); }); return suggestionsArr; - }, [secrets, folders, currentWorkspace?.environments, isPopupOpen, suggestionSource.value]); + }, [secrets, folders, currentProject?.environments, isPopupOpen, suggestionSource.value]); const handleSuggestionSelect = (selectIndex?: number) => { const selectedSuggestion = diff --git a/frontend/src/components/v2/SecretPathInput/SecretPathInput.tsx b/frontend/src/components/v2/SecretPathInput/SecretPathInput.tsx index a1d4fb2a2..a9c08f7ad 100644 --- a/frontend/src/components/v2/SecretPathInput/SecretPathInput.tsx +++ b/frontend/src/components/v2/SecretPathInput/SecretPathInput.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Popover from "@radix-ui/react-popover"; import { twMerge } from "tailwind-merge"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useDebounce } from "@app/hooks"; import { useGetFoldersByEnv } from "@app/hooks/api"; @@ -35,12 +35,12 @@ export const SecretPathInput = ({ const [highlightedIndex, setHighlightedIndex] = useState(-1); const [debouncedInputValue] = useDebounce(inputValue, 200); - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { folderNames: folders } = useGetFoldersByEnv({ path: secretPath, - environments: [environment || currentWorkspace?.environments?.[0].slug || ""], - projectId: workspaceId + environments: [environment || currentProject?.environments?.[0].slug || ""], + projectId }); useEffect(() => { diff --git a/frontend/src/context/OrgPermissionContext/types.ts b/frontend/src/context/OrgPermissionContext/types.ts index 60f069c1d..8e4f7514c 100644 --- a/frontend/src/context/OrgPermissionContext/types.ts +++ b/frontend/src/context/OrgPermissionContext/types.ts @@ -32,6 +32,7 @@ export enum OrgPermissionMachineIdentityAuthTemplateActions { export enum OrgPermissionSubjects { Workspace = "workspace", + Project = "project", Role = "role", Member = "member", Settings = "settings", @@ -109,6 +110,7 @@ export type AppConnectionSubjectFields = { export type OrgPermissionSet = | [OrgPermissionActions.Create, OrgPermissionSubjects.Workspace] + | [OrgPermissionActions.Create, OrgPermissionSubjects.Project] | [OrgPermissionActions.Read, OrgPermissionSubjects.Workspace] | [OrgPermissionActions, OrgPermissionSubjects.Role] | [OrgPermissionActions, OrgPermissionSubjects.Member] diff --git a/frontend/src/context/ProjectContext/ProjectContext.tsx b/frontend/src/context/ProjectContext/ProjectContext.tsx new file mode 100644 index 000000000..7256741ef --- /dev/null +++ b/frontend/src/context/ProjectContext/ProjectContext.tsx @@ -0,0 +1,22 @@ +import { useSuspenseQuery } from "@tanstack/react-query"; +import { useParams } from "@tanstack/react-router"; + +import { projectKeys } from "@app/hooks/api"; +import { fetchProjectById } from "@app/hooks/api/projects/queries"; + +export const useProject = () => { + const params = useParams({ + strict: false + }); + if (!params.projectId) { + throw new Error("Missing project id"); + } + + const { data: currentProject } = useSuspenseQuery({ + queryKey: projectKeys.getProjectById(params.projectId), + queryFn: () => fetchProjectById(params.projectId as string), + staleTime: Infinity + }); + + return { currentProject, projectId: currentProject.id }; +}; diff --git a/frontend/src/context/ProjectContext/index.tsx b/frontend/src/context/ProjectContext/index.tsx new file mode 100644 index 000000000..f87ed0a3d --- /dev/null +++ b/frontend/src/context/ProjectContext/index.tsx @@ -0,0 +1 @@ +export { useProject } from "./ProjectContext"; diff --git a/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx b/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx index a824f6fa6..871d5c338 100644 --- a/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx +++ b/frontend/src/context/ProjectPermissionContext/ProjectPermissionContext.tsx @@ -22,8 +22,8 @@ export const useProjectPermission = () => { const { data: { permission, membership, assumedPrivilegeDetails } } = useSuspenseQuery({ - queryKey: roleQueryKeys.getUserProjectPermissions({ workspaceId: projectId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId: projectId }), + queryKey: roleQueryKeys.getUserProjectPermissions({ projectId }), + queryFn: () => fetchUserProjectPermissions({ projectId }), staleTime: Infinity, select: (data) => { const rule = unpackRules>>(data.permissions); diff --git a/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx b/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx deleted file mode 100644 index 8bef13b31..000000000 --- a/frontend/src/context/WorkspaceContext/WorkspaceContext.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useSuspenseQuery } from "@tanstack/react-query"; -import { useParams } from "@tanstack/react-router"; - -import { workspaceKeys } from "@app/hooks/api"; -import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries"; - -export const useWorkspace = () => { - const params = useParams({ - strict: false - }); - if (!params.projectId) { - throw new Error("Missing project id"); - } - - const { data: currentWorkspace } = useSuspenseQuery({ - queryKey: workspaceKeys.getWorkspaceById(params.projectId), - queryFn: () => fetchWorkspaceById(params.projectId as string), - staleTime: Infinity - }); - - return { currentWorkspace }; -}; diff --git a/frontend/src/context/WorkspaceContext/index.tsx b/frontend/src/context/WorkspaceContext/index.tsx deleted file mode 100644 index b0c25d4da..000000000 --- a/frontend/src/context/WorkspaceContext/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { useWorkspace } from "./WorkspaceContext"; diff --git a/frontend/src/context/index.tsx b/frontend/src/context/index.tsx index bfb504664..fff370269 100644 --- a/frontend/src/context/index.tsx +++ b/frontend/src/context/index.tsx @@ -9,6 +9,7 @@ export { OrgPermissionSubjects, useOrgPermission } from "./OrgPermissionContext"; +export { useProject } from "./ProjectContext"; export type { TProjectPermission } from "./ProjectPermissionContext"; export { ProjectPermissionActions, @@ -29,4 +30,3 @@ export { export { useServerConfig } from "./ServerConfigContext"; export { useSubscription } from "./SubscriptionContext"; export { useUser } from "./UserContext"; -export { useWorkspace } from "./WorkspaceContext"; diff --git a/frontend/src/helpers/auditLogStreams.ts b/frontend/src/helpers/auditLogStreams.ts index eee2fc8da..faa132dd2 100644 --- a/frontend/src/helpers/auditLogStreams.ts +++ b/frontend/src/helpers/auditLogStreams.ts @@ -8,6 +8,7 @@ export const AUDIT_LOG_STREAM_PROVIDER_MAP: Record< LogProvider, { name: string; image?: string; icon?: IconDefinition; size?: number } > = { + [LogProvider.Azure]: { name: "Azure", image: "Microsoft Azure.png", size: 60 }, [LogProvider.Cribl]: { name: "Cribl", image: "Cribl.png", size: 60 }, [LogProvider.Custom]: { name: "Custom", icon: faCode }, [LogProvider.Datadog]: { name: "Datadog", image: "Datadog.png" }, @@ -25,6 +26,8 @@ export function getProviderUrl( return logStream.credentials.url; case LogProvider.Splunk: return `https://${logStream.credentials.hostname}:8088/services/collector/event`; + case LogProvider.Azure: + return `${logStream.credentials.dceUrl}/dataCollectionRules/${logStream.credentials.dcrId}/streams/Custom-${logStream.credentials.cltName}_CL`; default: throw new Error( `Unhandled provider in getProviderUrl: ${(logStream as TAuditLogStream).provider}` diff --git a/frontend/src/helpers/project.ts b/frontend/src/helpers/project.ts index 7c9185556..6227b9696 100644 --- a/frontend/src/helpers/project.ts +++ b/frontend/src/helpers/project.ts @@ -1,6 +1,6 @@ import { apiRequest } from "@app/config/request"; -import { createWorkspace } from "@app/hooks/api/workspace/queries"; -import { ProjectType, WorkspaceEnv } from "@app/hooks/api/workspace/types"; +import { createWorkspace } from "@app/hooks/api/projects/queries"; +import { ProjectEnv, ProjectType } from "@app/hooks/api/projects/types"; const secretsToBeAdded = [ { @@ -47,8 +47,8 @@ export const initProjectHelper = async ({ projectName }: { projectName: string } }); try { - const { data } = await apiRequest.post("/api/v3/secrets/batch/raw", { - workspaceId: project.id, + const { data } = await apiRequest.post("/api/v4/secrets/batch", { + projectId: project.id, environment: "dev", secretPath: "/", secrets: secretsToBeAdded @@ -74,7 +74,7 @@ export const getProjectBaseURL = (type: ProjectType) => { // @ts-expect-error akhilmhdh: will remove this later // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const getProjectHomePage = (type: ProjectType, environments: WorkspaceEnv[]) => { +export const getProjectHomePage = (type: ProjectType, environments: ProjectEnv[]) => { switch (type) { case ProjectType.SecretManager: return "/projects/secret-management/$projectId/overview" as const; diff --git a/frontend/src/hooks/api/accessApproval/queries.tsx b/frontend/src/hooks/api/accessApproval/queries.tsx index 44f260f66..2be6c9535 100644 --- a/frontend/src/hooks/api/accessApproval/queries.tsx +++ b/frontend/src/hooks/api/accessApproval/queries.tsx @@ -16,8 +16,8 @@ import { export const accessApprovalKeys = { getAccessApprovalPolicies: (projectSlug: string) => [{ projectSlug }, "access-approval-policies"] as const, - getAccessApprovalPolicyOfABoard: (workspaceId: string, environment: string) => - [{ workspaceId, environment }, "access-approval-policy"] as const, + getAccessApprovalPolicyOfABoard: (projectId: string, environment: string) => + [{ projectId, environment }, "access-approval-policy"] as const, getAccessApprovalRequests: ( projectSlug: string, diff --git a/frontend/src/hooks/api/accessApproval/types.ts b/frontend/src/hooks/api/accessApproval/types.ts index 5063f4fff..be698e469 100644 --- a/frontend/src/hooks/api/accessApproval/types.ts +++ b/frontend/src/hooks/api/accessApproval/types.ts @@ -1,7 +1,7 @@ import { EnforcementLevel, PolicyType } from "../policies/enums"; +import { ProjectEnv } from "../projects/types"; import { TProjectPermission } from "../roles/types"; import { ApprovalStatus } from "../secretApprovalRequest/types"; -import { WorkspaceEnv } from "../workspace/types"; export type TAccessApprovalPolicy = { id: string; @@ -9,7 +9,7 @@ export type TAccessApprovalPolicy = { approvals: number; secretPath: string; workspace: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; projectId: string; policyType: PolicyType; approversRequired: boolean; diff --git a/frontend/src/hooks/api/appConnections/queries.tsx b/frontend/src/hooks/api/appConnections/queries.tsx index 48c084a4e..a27ffdc10 100644 --- a/frontend/src/hooks/api/appConnections/queries.tsx +++ b/frontend/src/hooks/api/appConnections/queries.tsx @@ -14,7 +14,7 @@ import { TAppConnectionOption, TAppConnectionOptionMap } from "@app/hooks/api/appConnections/types/app-options"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; export const appConnectionKeys = { all: ["app-connection"] as const, diff --git a/frontend/src/hooks/api/appConnections/types/root-connection.ts b/frontend/src/hooks/api/appConnections/types/root-connection.ts index 3a90ca12b..96198265e 100644 --- a/frontend/src/hooks/api/appConnections/types/root-connection.ts +++ b/frontend/src/hooks/api/appConnections/types/root-connection.ts @@ -1,4 +1,4 @@ -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; export type TRootAppConnection = { id: string; diff --git a/frontend/src/hooks/api/assumePrivileges/mutations.tsx b/frontend/src/hooks/api/assumePrivileges/mutations.tsx index 50e4e5b6c..687882fe8 100644 --- a/frontend/src/hooks/api/assumePrivileges/mutations.tsx +++ b/frontend/src/hooks/api/assumePrivileges/mutations.tsx @@ -8,7 +8,7 @@ export const useAssumeProjectPrivileges = () => useMutation({ mutationFn: async ({ projectId, actorId, actorType }: TProjectAssumePrivilegesDTO) => { const { data } = await apiRequest.post<{ message: string }>( - `/api/v1/workspace/${projectId}/assume-privileges`, + `/api/v1/projects/${projectId}/assume-privileges`, { actorId, actorType } ); @@ -20,7 +20,7 @@ export const useRemoveAssumeProjectPrivilege = () => useMutation({ mutationFn: async ({ projectId }: { projectId: string }) => { const { data } = await apiRequest.delete<{ message: string }>( - `/api/v1/workspace/${projectId}/assume-privileges` + `/api/v1/projects/${projectId}/assume-privileges` ); return data; diff --git a/frontend/src/hooks/api/auditLogStreams/enums.ts b/frontend/src/hooks/api/auditLogStreams/enums.ts index 78233f774..ebef18574 100644 --- a/frontend/src/hooks/api/auditLogStreams/enums.ts +++ b/frontend/src/hooks/api/auditLogStreams/enums.ts @@ -1,4 +1,5 @@ export enum LogProvider { + Azure = "azure", Cribl = "cribl", Custom = "custom", Datadog = "datadog", diff --git a/frontend/src/hooks/api/auditLogStreams/types/index.ts b/frontend/src/hooks/api/auditLogStreams/types/index.ts index a360cd677..f780510c2 100644 --- a/frontend/src/hooks/api/auditLogStreams/types/index.ts +++ b/frontend/src/hooks/api/auditLogStreams/types/index.ts @@ -1,4 +1,5 @@ import { LogProvider } from "../enums"; +import { TAzureProviderLogStream } from "./providers/azure-provider"; import { TCriblProviderLogStream } from "./providers/cribl-provider"; import { TCustomProviderLogStream } from "./providers/custom-provider"; import { TDatadogProviderLogStream } from "./providers/datadog-provider"; @@ -8,9 +9,11 @@ export type TAuditLogStream = | TCustomProviderLogStream | TDatadogProviderLogStream | TSplunkProviderLogStream + | TAzureProviderLogStream | TCriblProviderLogStream; export type TAuditLogStreamProviderMap = { + [LogProvider.Azure]: TAzureProviderLogStream; [LogProvider.Cribl]: TCriblProviderLogStream; [LogProvider.Custom]: TCustomProviderLogStream; [LogProvider.Datadog]: TDatadogProviderLogStream; diff --git a/frontend/src/hooks/api/auditLogStreams/types/providers/azure-provider.ts b/frontend/src/hooks/api/auditLogStreams/types/providers/azure-provider.ts new file mode 100644 index 000000000..3086fd7cc --- /dev/null +++ b/frontend/src/hooks/api/auditLogStreams/types/providers/azure-provider.ts @@ -0,0 +1,14 @@ +import { LogProvider } from "../../enums"; +import { TRootProviderLogStream } from "./root-provider"; + +export type TAzureProviderLogStream = TRootProviderLogStream & { + provider: LogProvider.Azure; + credentials: { + tenantId: string; + clientId: string; + clientSecret: string; + dceUrl: string; + dcrId: string; + cltName: string; + }; +}; diff --git a/frontend/src/hooks/api/auditLogs/constants.tsx b/frontend/src/hooks/api/auditLogs/constants.tsx index 1166da805..195f90083 100644 --- a/frontend/src/hooks/api/auditLogs/constants.tsx +++ b/frontend/src/hooks/api/auditLogs/constants.tsx @@ -20,7 +20,7 @@ export const eventToNameMap: { [K in EventType]: string } = { [EventType.CREATE_SECRET]: "Create secret", [EventType.UPDATE_SECRET]: "Update secret", [EventType.DELETE_SECRET]: "Delete secret", - [EventType.GET_WORKSPACE_KEY]: "Read project key", + [EventType.GET_PROJECT_KEY]: "Read project key", [EventType.AUTHORIZE_INTEGRATION]: "Authorize integration", [EventType.UPDATE_INTEGRATION_AUTH]: "Update integration auth", [EventType.UNAUTHORIZE_INTEGRATION]: "Unauthorize integration", @@ -45,8 +45,8 @@ export const eventToNameMap: { [K in EventType]: string } = { [EventType.CREATE_ENVIRONMENT]: "Create environment", [EventType.UPDATE_ENVIRONMENT]: "Update environment", [EventType.DELETE_ENVIRONMENT]: "Delete environment", - [EventType.ADD_WORKSPACE_MEMBER]: "Add member", - [EventType.REMOVE_WORKSPACE_MEMBER]: "Remove member", + [EventType.ADD_PROJECT_MEMBER]: "Add member", + [EventType.REMOVE_PROJECT_MEMBER]: "Remove member", [EventType.CREATE_FOLDER]: "Create folder", [EventType.UPDATE_FOLDER]: "Update folder", [EventType.DELETE_FOLDER]: "Delete folder", @@ -58,8 +58,8 @@ export const eventToNameMap: { [K in EventType]: string } = { [EventType.CREATE_SECRET_IMPORT]: "Create secret import", [EventType.UPDATE_SECRET_IMPORT]: "Update secret import", [EventType.DELETE_SECRET_IMPORT]: "Delete secret import", - [EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS]: "Update denied permissions", - [EventType.UPDATE_USER_WORKSPACE_ROLE]: "Update user role", + [EventType.UPDATE_USER_PROJECT_DENIED_PERMISSIONS]: "Update denied permissions", + [EventType.UPDATE_USER_PROJECT_ROLE]: "Update user role", [EventType.CREATE_CA]: "Create CA", [EventType.GET_CA]: "Get CA", [EventType.UPDATE_CA]: "Update CA", diff --git a/frontend/src/hooks/api/auditLogs/enums.tsx b/frontend/src/hooks/api/auditLogs/enums.tsx index 3ea573bdb..7ad592d8c 100644 --- a/frontend/src/hooks/api/auditLogs/enums.tsx +++ b/frontend/src/hooks/api/auditLogs/enums.tsx @@ -26,7 +26,7 @@ export enum EventType { CREATE_SECRET = "create-secret", UPDATE_SECRET = "update-secret", DELETE_SECRET = "delete-secret", - GET_WORKSPACE_KEY = "get-workspace-key", + GET_PROJECT_KEY = "get-project-key", AUTHORIZE_INTEGRATION = "authorize-integration", UPDATE_INTEGRATION_AUTH = "update-integration-auth", UNAUTHORIZE_INTEGRATION = "unauthorize-integration", @@ -58,8 +58,8 @@ export enum EventType { CREATE_ENVIRONMENT = "create-environment", UPDATE_ENVIRONMENT = "update-environment", DELETE_ENVIRONMENT = "delete-environment", - ADD_WORKSPACE_MEMBER = "add-workspace-member", - REMOVE_WORKSPACE_MEMBER = "remove-workspace-member", + ADD_PROJECT_MEMBER = "add-project-member", + REMOVE_PROJECT_MEMBER = "remove-project-member", CREATE_FOLDER = "create-folder", UPDATE_FOLDER = "update-folder", DELETE_FOLDER = "delete-folder", @@ -71,8 +71,8 @@ export enum EventType { CREATE_SECRET_IMPORT = "create-secret-import", UPDATE_SECRET_IMPORT = "update-secret-import", DELETE_SECRET_IMPORT = "delete-secret-import", - UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role", - UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions", + UPDATE_USER_PROJECT_ROLE = "update-user-project-role", + UPDATE_USER_PROJECT_DENIED_PERMISSIONS = "update-user-project-denied-permissions", CREATE_CA = "create-certificate-authority", GET_CA = "get-certificate-authority", UPDATE_CA = "update-certificate-authority", diff --git a/frontend/src/hooks/api/auditLogs/queries.tsx b/frontend/src/hooks/api/auditLogs/queries.tsx index 8cb438c92..5e25d8104 100644 --- a/frontend/src/hooks/api/auditLogs/queries.tsx +++ b/frontend/src/hooks/api/auditLogs/queries.tsx @@ -7,10 +7,10 @@ import { TReactQueryOptions } from "@app/types/reactQuery"; import { Actor, AuditLog, TGetAuditLogsFilter } from "./types"; export const auditLogKeys = { - getAuditLogs: (workspaceId: string | null, filters: TGetAuditLogsFilter) => - [{ workspaceId, filters }, "audit-logs"] as const, - getAuditLogActorFilterOpts: (workspaceId: string) => - [{ workspaceId }, "audit-log-actor-filters"] as const + getAuditLogs: (projectId: string | null, filters: TGetAuditLogsFilter) => + [{ projectId, filters }, "audit-logs"] as const, + getAuditLogActorFilterOpts: (projectId: string) => + [{ projectId }, "audit-log-actor-filters"] as const }; export const useGetAuditLogs = ( @@ -56,12 +56,12 @@ export const useGetAuditLogs = ( }); }; -export const useGetAuditLogActorFilterOpts = (workspaceId: string) => { +export const useGetAuditLogActorFilterOpts = (projectId: string) => { return useQuery({ - queryKey: auditLogKeys.getAuditLogActorFilterOpts(workspaceId), + queryKey: auditLogKeys.getAuditLogActorFilterOpts(projectId), queryFn: async () => { const { data } = await apiRequest.get<{ actors: Actor[] }>( - `/api/v1/workspace/${workspaceId}/audit-logs/filters/actors` + `/api/v1/projects/${projectId}/audit-logs/filters/actors` ); return data.actors; } diff --git a/frontend/src/hooks/api/auditLogs/types.tsx b/frontend/src/hooks/api/auditLogs/types.tsx index 1ca819e60..f09924d26 100644 --- a/frontend/src/hooks/api/auditLogs/types.tsx +++ b/frontend/src/hooks/api/auditLogs/types.tsx @@ -129,7 +129,7 @@ interface DeleteSecretEvent { } interface GetWorkspaceKeyEvent { - type: EventType.GET_WORKSPACE_KEY; + type: EventType.GET_PROJECT_KEY; metadata: { keyId: string; }; @@ -361,7 +361,7 @@ interface DeleteEnvironmentEvent { } interface AddWorkspaceMemberEvent { - type: EventType.ADD_WORKSPACE_MEMBER; + type: EventType.ADD_PROJECT_MEMBER; metadata: { userId: string; email: string; @@ -369,7 +369,7 @@ interface AddWorkspaceMemberEvent { } interface RemoveWorkspaceMemberEvent { - type: EventType.REMOVE_WORKSPACE_MEMBER; + type: EventType.REMOVE_PROJECT_MEMBER; metadata: { userId: string; email: string; @@ -500,7 +500,7 @@ interface DeleteSecretImportEvent { } interface UpdateUserRole { - type: EventType.UPDATE_USER_WORKSPACE_ROLE; + type: EventType.UPDATE_USER_PROJECT_ROLE; metadata: { userId: string; email: string; @@ -510,7 +510,7 @@ interface UpdateUserRole { } interface UpdateUserDeniedPermissions { - type: EventType.UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS; + type: EventType.UPDATE_USER_PROJECT_DENIED_PERMISSIONS; metadata: { userId: string; email: string; diff --git a/frontend/src/hooks/api/auth/queries.tsx b/frontend/src/hooks/api/auth/queries.tsx index cb7e3f64c..d41a4d115 100644 --- a/frontend/src/hooks/api/auth/queries.tsx +++ b/frontend/src/hooks/api/auth/queries.tsx @@ -5,8 +5,8 @@ import { apiRequest } from "@app/config/request"; import { SessionStorageKeys } from "@app/const"; import { organizationKeys } from "../organization/queries"; +import { projectKeys } from "../projects"; import { setAuthToken } from "../reactQuery"; -import { workspaceKeys } from "../workspace"; import { CompleteAccountDTO, CompleteAccountSignupDTO, @@ -101,7 +101,7 @@ export const useSelectOrganization = () => { }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: [organizationKeys.getUserOrganizations, workspaceKeys.getAllUserWorkspace] + queryKey: [organizationKeys.getUserOrganizations, projectKeys.getAllUserProjects] }); } }); diff --git a/frontend/src/hooks/api/ca/mutations.tsx b/frontend/src/hooks/api/ca/mutations.tsx index f6204d4fc..a14a0244b 100644 --- a/frontend/src/hooks/api/ca/mutations.tsx +++ b/frontend/src/hooks/api/ca/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { CaType } from "./enums"; import { caKeys } from "./queries"; import { @@ -118,8 +118,8 @@ export const useImportCaCertificate = (projectId: string) => { ); return data; }, - onSuccess: (_, { caId, projectSlug }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceCas({ projectSlug }) }); + onSuccess: (_, { caId }) => { + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectCas({ projectId }) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCerts(caId) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCert(caId) }); queryClient.invalidateQueries({ @@ -142,7 +142,7 @@ export const useCreateCertificate = () => { }, onSuccess: (_, { projectSlug }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.forWorkspaceCertificates(projectSlug) + queryKey: projectKeys.forProjectCertificates(projectSlug) }); } }); @@ -158,8 +158,8 @@ export const useRenewCa = () => { ); return data; }, - onSuccess: (_, { caId, projectSlug }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceCas({ projectSlug }) }); + onSuccess: ({ projectId }, { caId }) => { + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectCas({ projectId }) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaById(caId) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCert(caId) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCerts(caId) }); diff --git a/frontend/src/hooks/api/ca/types.ts b/frontend/src/hooks/api/ca/types.ts index 336688ca4..0443dd5e9 100644 --- a/frontend/src/hooks/api/ca/types.ts +++ b/frontend/src/hooks/api/ca/types.ts @@ -182,4 +182,5 @@ export type TRenewCaResponse = { certificate: string; certificateChain: string; serialNumber: string; + projectId: string; }; diff --git a/frontend/src/hooks/api/certificateTemplates/mutations.tsx b/frontend/src/hooks/api/certificateTemplates/mutations.tsx index d1069e7e6..24a7d0e5f 100644 --- a/frontend/src/hooks/api/certificateTemplates/mutations.tsx +++ b/frontend/src/hooks/api/certificateTemplates/mutations.tsx @@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; import { caKeys } from "../ca/queries"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { certTemplateKeys } from "./queries"; import { TCertificateTemplate, @@ -29,7 +29,7 @@ export const useCreateCertTemplate = () => { }, onSuccess: ({ caId }, { projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceCertificateTemplates(projectId) + queryKey: projectKeys.getProjectCertificateTemplates(projectId) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCertTemplates(caId) }); } @@ -49,7 +49,7 @@ export const useUpdateCertTemplate = () => { }, onSuccess: ({ caId }, { projectId, id }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceCertificateTemplates(projectId) + queryKey: projectKeys.getProjectCertificateTemplates(projectId) }); queryClient.invalidateQueries({ queryKey: certTemplateKeys.getCertTemplateById(id) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCertTemplates(caId) }); @@ -68,7 +68,7 @@ export const useDeleteCertTemplate = () => { }, onSuccess: ({ caId }, { projectId, id }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceCertificateTemplates(projectId) + queryKey: projectKeys.getProjectCertificateTemplates(projectId) }); queryClient.invalidateQueries({ queryKey: certTemplateKeys.getCertTemplateById(id) }); queryClient.invalidateQueries({ queryKey: caKeys.getCaCertTemplates(caId) }); diff --git a/frontend/src/hooks/api/certificates/mutations.tsx b/frontend/src/hooks/api/certificates/mutations.tsx index 12f8e834b..77a3dab72 100644 --- a/frontend/src/hooks/api/certificates/mutations.tsx +++ b/frontend/src/hooks/api/certificates/mutations.tsx @@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; import { pkiSubscriberKeys } from "../pkiSubscriber/queries"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { TCertificate, TDeleteCertDTO, @@ -25,7 +25,7 @@ export const useDeleteCert = () => { }, onSuccess: (_, { projectSlug }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.forWorkspaceCertificates(projectSlug) + queryKey: projectKeys.forProjectCertificates(projectSlug) }); } }); @@ -47,7 +47,7 @@ export const useRevokeCert = () => { }, onSuccess: (_, { projectSlug }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.forWorkspaceCertificates(projectSlug) + queryKey: projectKeys.forProjectCertificates(projectSlug) }); queryClient.invalidateQueries({ queryKey: pkiSubscriberKeys.allPkiSubscriberCertificates() @@ -68,7 +68,7 @@ export const useImportCertificate = () => { }, onSuccess: (_, { projectSlug }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.forWorkspaceCertificates(projectSlug) + queryKey: projectKeys.forProjectCertificates(projectSlug) }); } }); diff --git a/frontend/src/hooks/api/folderCommits/queries.tsx b/frontend/src/hooks/api/folderCommits/queries.tsx index 1bca7ce9a..4d37a4f7b 100644 --- a/frontend/src/hooks/api/folderCommits/queries.tsx +++ b/frontend/src/hooks/api/folderCommits/queries.tsx @@ -7,27 +7,27 @@ import { Commit, CommitHistoryItem, CommitWithChanges, RollbackPreview } from ". export const commitKeys = { count: ({ - workspaceId, + projectId, environment, directory }: { - workspaceId: string; + projectId: string; environment: string; directory?: string; - }) => [{ workspaceId, environment, directory }, "folder-commits-count"] as const, + }) => [{ projectId, environment, directory }, "folder-commits-count"] as const, history: ({ - workspaceId, + projectId, environment, directory }: { - workspaceId: string; + projectId: string; environment: string; directory?: string; - }) => [{ workspaceId, environment, directory }, "folder-commits"] as const, + }) => [{ projectId, environment, directory }, "folder-commits"] as const, - details: ({ workspaceId, commitId }: { workspaceId: string; commitId: string }) => - [{ workspaceId, commitId }, "commit-details"] as const, + details: ({ projectId, commitId }: { projectId: string; commitId: string }) => + [{ projectId, commitId }, "commit-details"] as const, rollbackPreview: ({ folderId, @@ -45,11 +45,11 @@ export const commitKeys = { }; const fetchFolderCommitsCount = async ({ - workspaceId, + projectId, environment, directory }: { - workspaceId: string; + projectId: string; environment: string; directory?: string; }) => { @@ -59,7 +59,7 @@ const fetchFolderCommitsCount = async ({ params: { environment, path: directory, - projectId: workspaceId + projectId } } ); @@ -67,7 +67,7 @@ const fetchFolderCommitsCount = async ({ }; const fetchFolderCommitHistory = async ( - workspaceId: string, + projectId: string, environment: string, directory: string, offset: number = 0, @@ -87,7 +87,7 @@ const fetchFolderCommitHistory = async ( params: { environment, path: directory, - projectId: workspaceId, + projectId, offset, limit, search, @@ -97,12 +97,12 @@ const fetchFolderCommitHistory = async ( return res.data; }; -export const fetchCommitDetails = async (workspaceId: string, commitId: string) => { +export const fetchCommitDetails = async (projectId: string, commitId: string) => { const { data } = await apiRequest.get( `/api/v1/pit/commits/${commitId}/changes`, { params: { - projectId: workspaceId + projectId } } ); @@ -113,7 +113,7 @@ export const fetchRollbackPreview = async ( folderId: string, commitId: string, envSlug: string, - workspaceId: string, + projectId: string, deepRollback: boolean, secretPath: string ): Promise => { @@ -125,7 +125,7 @@ export const fetchRollbackPreview = async ( environment: envSlug, deepRollback, secretPath, - projectId: workspaceId + projectId } } ); @@ -135,7 +135,7 @@ export const fetchRollbackPreview = async ( const fetchRollback = async ( folderId: string, commitId: string, - workspaceId: string, + projectId: string, deepRollback: boolean, message?: string, envSlug?: string @@ -147,17 +147,17 @@ const fetchRollback = async ( deepRollback, message, environment: envSlug, - projectId: workspaceId + projectId } ); return data; }; -const fetchRevert = async (commitId: string, workspaceId: string) => { +const fetchRevert = async (commitId: string, projectId: string) => { const { data } = await apiRequest.post<{ success: boolean; message: string }>( `/api/v1/pit/commits/${commitId}/revert`, { - projectId: workspaceId + projectId } ); return data; @@ -180,9 +180,9 @@ export const useCommitRevert = ({ onSuccess: () => { queryClient.invalidateQueries({ queryKey: [ - commitKeys.details({ workspaceId: projectId, commitId }), - commitKeys.history({ workspaceId: projectId, environment, directory }), - commitKeys.count({ workspaceId: projectId, environment, directory }) + commitKeys.details({ projectId, commitId }), + commitKeys.history({ projectId, environment, directory }), + commitKeys.count({ projectId, environment, directory }) ] }); } @@ -190,7 +190,7 @@ export const useCommitRevert = ({ }; export const useCommitRollback = ({ - workspaceId, + projectId, commitId, folderId, deepRollback, @@ -198,7 +198,7 @@ export const useCommitRollback = ({ directory, envSlug }: { - workspaceId: string; + projectId: string; commitId: string; folderId: string; deepRollback: boolean; @@ -209,13 +209,13 @@ export const useCommitRollback = ({ const queryClient = useQueryClient(); return useMutation({ mutationFn: (message: string) => - fetchRollback(folderId, commitId, workspaceId, deepRollback, message, envSlug), + fetchRollback(folderId, commitId, projectId, deepRollback, message, envSlug), onSuccess: () => { queryClient.invalidateQueries({ queryKey: [ - commitKeys.details({ workspaceId, commitId }), - commitKeys.history({ workspaceId, environment, directory }), - commitKeys.count({ workspaceId, environment, directory }) + commitKeys.details({ projectId, commitId }), + commitKeys.history({ projectId, environment, directory }), + commitKeys.count({ projectId, environment, directory }) ] }); } @@ -223,31 +223,31 @@ export const useCommitRollback = ({ }; export const useGetFolderCommitsCount = ({ - workspaceId, + projectId, environment, directory, isPaused }: { - workspaceId: string; + projectId: string; environment: string; directory: string; isPaused?: boolean; }) => useQuery({ - enabled: Boolean(workspaceId && environment) && !isPaused, - queryKey: commitKeys.count({ workspaceId, environment, directory }), - queryFn: () => fetchFolderCommitsCount({ workspaceId, environment, directory }) + enabled: Boolean(projectId && environment) && !isPaused, + queryKey: commitKeys.count({ projectId, environment, directory }), + queryFn: () => fetchFolderCommitsCount({ projectId, environment, directory }) }); export const useGetFolderCommitHistory = ({ - workspaceId, + projectId, environment, directory, limit = 20, search, sort = "desc" }: { - workspaceId: string; + projectId: string; environment: string; directory: string; limit?: number; @@ -256,10 +256,10 @@ export const useGetFolderCommitHistory = ({ }) => { return useInfiniteQuery({ initialPageParam: 0, - queryKey: [commitKeys.history({ workspaceId, environment, directory }), limit, search, sort], + queryKey: [commitKeys.history({ projectId, environment, directory }), limit, search, sort], queryFn: ({ pageParam }) => - fetchFolderCommitHistory(workspaceId, environment, directory, pageParam, limit, search, sort), - enabled: Boolean(workspaceId && environment), + fetchFolderCommitHistory(projectId, environment, directory, pageParam, limit, search, sort), + enabled: Boolean(projectId && environment), select: (data) => { return (data?.pages ?? []) ?.map((page) => page.commits) @@ -280,11 +280,11 @@ export const useGetFolderCommitHistory = ({ }); }; -export const useGetCommitDetails = (workspaceId: string, commitId: string) => { +export const useGetCommitDetails = (projectId: string, commitId: string) => { return useQuery({ - queryKey: commitKeys.details({ workspaceId, commitId }), - queryFn: () => fetchCommitDetails(workspaceId, commitId), - enabled: Boolean(workspaceId) && Boolean(commitId) + queryKey: commitKeys.details({ projectId, commitId }), + queryFn: () => fetchCommitDetails(projectId, commitId), + enabled: Boolean(projectId) && Boolean(commitId) }); }; diff --git a/frontend/src/hooks/api/groups/queries.tsx b/frontend/src/hooks/api/groups/queries.tsx index 6fbe0ec13..ca524066f 100644 --- a/frontend/src/hooks/api/groups/queries.tsx +++ b/frontend/src/hooks/api/groups/queries.tsx @@ -138,7 +138,7 @@ export const useListProjectGroupUsers = ({ }); const { data } = await apiRequest.get<{ users: TGroupUser[]; totalCount: number }>( - `/api/v2/workspace/${projectId}/groups/${id}/users`, + `/api/v1/projects/${projectId}/groups/${id}/users`, { params } diff --git a/frontend/src/hooks/api/identities/types.ts b/frontend/src/hooks/api/identities/types.ts index 36f9eae4e..af8e401d7 100644 --- a/frontend/src/hooks/api/identities/types.ts +++ b/frontend/src/hooks/api/identities/types.ts @@ -1,7 +1,7 @@ import { OrderByDirection } from "../generic/types"; import { OrgIdentityOrderBy } from "../organization/types"; +import { Project, ProjectUserMembershipTemporaryMode } from "../projects/types"; import { TOrgRole } from "../roles/types"; -import { ProjectUserMembershipTemporaryMode, Workspace } from "../workspace/types"; import { IdentityAuthMethod, IdentityJwtConfigurationType } from "./enums"; export type IdentityTrustedIp = { @@ -54,7 +54,7 @@ export type IdentityMembershipOrg = { export type IdentityMembership = { id: string; identity: Identity; - project: Pick; + project: Pick; roles: Array< { id: string; diff --git a/frontend/src/hooks/api/index.tsx b/frontend/src/hooks/api/index.tsx index 78dcd3b79..d65c7e72c 100644 --- a/frontend/src/hooks/api/index.tsx +++ b/frontend/src/hooks/api/index.tsx @@ -20,7 +20,6 @@ export * from "./identityProjectAdditionalPrivilege"; export * from "./incidentContacts"; export * from "./integrationAuth"; export * from "./integrations"; -export * from "./keys"; export * from "./kms"; export * from "./ldapConfig"; export * from "./oidcConfig"; @@ -29,6 +28,7 @@ export * from "./organization"; export * from "./pkiAlerts"; export * from "./pkiCollections"; export * from "./pkiSubscriber"; +export * from "./projects"; export * from "./projectUserAdditionalPrivilege"; export * from "./rateLimit"; export * from "./roles"; @@ -54,4 +54,3 @@ export * from "./trustedIps"; export * from "./users"; export * from "./webhooks"; export * from "./workflowIntegrations"; -export * from "./workspace"; diff --git a/frontend/src/hooks/api/integrationAuth/queries.tsx b/frontend/src/hooks/api/integrationAuth/queries.tsx index 044ec8d2a..f6c936480 100644 --- a/frontend/src/hooks/api/integrationAuth/queries.tsx +++ b/frontend/src/hooks/api/integrationAuth/queries.tsx @@ -3,7 +3,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; import { TReactQueryOptions } from "@app/types/reactQuery"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { App, BitbucketEnvironment, @@ -970,7 +970,7 @@ export const useAuthorizeIntegration = () => { }, onSuccess: (res) => { queryClient.invalidateQueries({ - queryKey: { queryKey: workspaceKeys.getWorkspaceAuthorization(res.workspace) } + queryKey: { queryKey: projectKeys.getProjectAuthorization(res.workspace) } }); } }); @@ -1016,7 +1016,7 @@ export const useSaveIntegrationAccessToken = () => { }, onSuccess: (res) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceAuthorization(res.workspace) + queryKey: projectKeys.getProjectAuthorization(res.workspace) }); } }); @@ -1035,10 +1035,10 @@ export const useDeleteIntegrationAuths = () => { ), onSuccess: (_, { workspaceId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceAuthorization(workspaceId) + queryKey: projectKeys.getProjectAuthorization(workspaceId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIntegrations(workspaceId) + queryKey: projectKeys.getProjectIntegrations(workspaceId) }); } }); @@ -1052,10 +1052,10 @@ export const useDeleteIntegrationAuth = () => { mutationFn: ({ id }) => apiRequest.delete(`/api/v1/integration-auth/${id}`), onSuccess: (_, { workspaceId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceAuthorization(workspaceId) + queryKey: projectKeys.getProjectAuthorization(workspaceId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIntegrations(workspaceId) + queryKey: projectKeys.getProjectIntegrations(workspaceId) }); } }); diff --git a/frontend/src/hooks/api/integrations/queries.tsx b/frontend/src/hooks/api/integrations/queries.tsx index a439f8caa..69519a5a4 100644 --- a/frontend/src/hooks/api/integrations/queries.tsx +++ b/frontend/src/hooks/api/integrations/queries.tsx @@ -3,7 +3,7 @@ import { useMutation, useQuery, useQueryClient, UseQueryOptions } from "@tanstac import { createNotification } from "@app/components/notifications"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { IntegrationMetadataSyncMode, TCloudIntegration, @@ -121,7 +121,7 @@ export const useCreateIntegration = () => { }, onSuccess: (res) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIntegrations(res.workspace) + queryKey: projectKeys.getProjectIntegrations(res.workspace) }); } }); @@ -141,10 +141,10 @@ export const useDeleteIntegration = () => { ), onSuccess: (_, { workspaceId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIntegrations(workspaceId) + queryKey: projectKeys.getProjectIntegrations(workspaceId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceAuthorization(workspaceId) + queryKey: projectKeys.getProjectAuthorization(workspaceId) }); } }); diff --git a/frontend/src/hooks/api/keys/index.tsx b/frontend/src/hooks/api/keys/index.tsx deleted file mode 100644 index cd4f0aea8..000000000 --- a/frontend/src/hooks/api/keys/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { useGetUserWsKey, useUploadWsKey } from "./queries"; diff --git a/frontend/src/hooks/api/keys/queries.tsx b/frontend/src/hooks/api/keys/queries.tsx deleted file mode 100644 index f902f85d3..000000000 --- a/frontend/src/hooks/api/keys/queries.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useMutation, useQuery } from "@tanstack/react-query"; - -import { apiRequest } from "@app/config/request"; - -import { UploadWsKeyDTO, UserWsKeyPair } from "./types"; - -const encKeyKeys = { - getUserWorkspaceKey: (workspaceID: string) => ["workspace-key-pair", { workspaceID }] as const -}; - -export const fetchUserWsKey = async (projectId: string) => { - const { data } = await apiRequest.get( - `/api/v2/workspace/${projectId}/encrypted-key` - ); - - return data; -}; - -export const useGetUserWsKey = (workspaceID: string) => - useQuery({ - queryKey: encKeyKeys.getUserWorkspaceKey(workspaceID), - queryFn: () => fetchUserWsKey(workspaceID), - enabled: Boolean(workspaceID) - }); - -// mutations -export const uploadWsKey = async ({ workspaceId, userId, encryptedKey, nonce }: UploadWsKeyDTO) => { - return apiRequest.post(`/api/v1/workspace/${workspaceId}/key`, { - key: { userId, encryptedKey, nonce } - }); -}; - -export const useUploadWsKey = () => - useMutation({ - mutationFn: async ({ encryptedKey, nonce, userId, workspaceId }) => { - return uploadWsKey({ - workspaceId, - userId, - encryptedKey, - nonce - }); - } - }); diff --git a/frontend/src/hooks/api/keys/types.ts b/frontend/src/hooks/api/keys/types.ts deleted file mode 100644 index fc455deaf..000000000 --- a/frontend/src/hooks/api/keys/types.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type UserWsKeyPair = { - id: string; - encryptedKey: string; - nonce: string; - sender: Sender; - receiver: string; - workspace: string; - createdAt: string; - updatedAt: string; - __v: number; -}; - -export type Sender = { - id: string; - email: string; - createdAt: string; - updatedAt: string; - __v: number; - firstName: string; - lastName: string; - publicKey: string; -}; - -export type UploadWsKeyDTO = { - userId: string; - encryptedKey: string; - nonce: string; - workspaceId: string; -}; diff --git a/frontend/src/hooks/api/kms/mutations.tsx b/frontend/src/hooks/api/kms/mutations.tsx index 2bf27bf6a..4fb0a5af5 100644 --- a/frontend/src/hooks/api/kms/mutations.tsx +++ b/frontend/src/hooks/api/kms/mutations.tsx @@ -75,7 +75,7 @@ export const useUpdateProjectKms = (projectId: string) => { mutationFn: async ( updatedData: { type: KmsType.Internal } | { type: KmsType.External; kmsId: string } ) => { - const { data } = await apiRequest.patch(`/api/v1/workspace/${projectId}/kms`, { + const { data } = await apiRequest.patch(`/api/v1/projects/${projectId}/kms`, { kms: updatedData }); @@ -91,7 +91,7 @@ export const useLoadProjectKmsBackup = (projectId: string) => { const queryClient = useQueryClient(); return useMutation({ mutationFn: async (backup: string) => { - const { data } = await apiRequest.post(`/api/v1/workspace/${projectId}/kms/backup`, { + const { data } = await apiRequest.post(`/api/v1/projects/${projectId}/kms/backup`, { backup }); diff --git a/frontend/src/hooks/api/kms/queries.tsx b/frontend/src/hooks/api/kms/queries.tsx index 9efa9cc51..97d25376c 100644 --- a/frontend/src/hooks/api/kms/queries.tsx +++ b/frontend/src/hooks/api/kms/queries.tsx @@ -49,7 +49,7 @@ export const useGetActiveProjectKms = (projectId: string) => { name: string; isExternal: string; }; - }>(`/api/v1/workspace/${projectId}/kms`); + }>(`/api/v1/projects/${projectId}/kms`); return secretManagerKmsKey; } }); @@ -58,7 +58,7 @@ export const useGetActiveProjectKms = (projectId: string) => { export const fetchProjectKmsBackup = async (projectId: string) => { const { data } = await apiRequest.get<{ secretManager: string; - }>(`/api/v1/workspace/${projectId}/kms/backup`); + }>(`/api/v1/projects/${projectId}/kms/backup`); return data; }; diff --git a/frontend/src/hooks/api/migration/mutations.tsx b/frontend/src/hooks/api/migration/mutations.tsx index 182797954..b2694b458 100644 --- a/frontend/src/hooks/api/migration/mutations.tsx +++ b/frontend/src/hooks/api/migration/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; export const useImportEnvKey = () => { const queryClient = useQueryClient(); @@ -34,7 +34,7 @@ export const useImportEnvKey = () => { }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); diff --git a/frontend/src/hooks/api/pkiAlerts/mutations.tsx b/frontend/src/hooks/api/pkiAlerts/mutations.tsx index 34397c141..df48a6aab 100644 --- a/frontend/src/hooks/api/pkiAlerts/mutations.tsx +++ b/frontend/src/hooks/api/pkiAlerts/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { pkiAlertKeys } from "./queries"; import { TCreatePkiAlertDTO, TDeletePkiAlertDTO, TPkiAlert, TUpdatePkiAlertDTO } from "./types"; @@ -14,7 +14,7 @@ export const useCreatePkiAlert = () => { return alert; }, onSuccess: (_, { projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspacePkiAlerts(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectPkiAlerts(projectId) }); } }); }; @@ -30,7 +30,7 @@ export const useUpdatePkiAlert = () => { return alert; }, onSuccess: (_, { projectId, alertId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspacePkiAlerts(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectPkiAlerts(projectId) }); queryClient.invalidateQueries({ queryKey: pkiAlertKeys.getPkiAlertById(alertId) }); } }); @@ -44,7 +44,7 @@ export const useDeletePkiAlert = () => { return alert; }, onSuccess: (_, { projectId, alertId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspacePkiAlerts(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectPkiAlerts(projectId) }); queryClient.invalidateQueries({ queryKey: pkiAlertKeys.getPkiAlertById(alertId) }); } }); diff --git a/frontend/src/hooks/api/pkiCollections/mutations.tsx b/frontend/src/hooks/api/pkiCollections/mutations.tsx index af1f0af18..a06afcd09 100644 --- a/frontend/src/hooks/api/pkiCollections/mutations.tsx +++ b/frontend/src/hooks/api/pkiCollections/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { pkiCollectionKeys } from "./queries"; import { TAddItemToPkiCollectionDTO, @@ -26,7 +26,7 @@ export const useCreatePkiCollection = () => { }, onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspacePkiCollections(projectId) + queryKey: projectKeys.getProjectPkiCollections(projectId) }); } }); @@ -44,7 +44,7 @@ export const useUpdatePkiCollection = () => { }, onSuccess: (_, { projectId, collectionId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspacePkiCollections(projectId) + queryKey: projectKeys.getProjectPkiCollections(projectId) }); queryClient.invalidateQueries({ queryKey: pkiCollectionKeys.getPkiCollectionById(collectionId) @@ -64,7 +64,7 @@ export const useDeletePkiCollection = () => { }, onSuccess: (_, { projectId, collectionId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspacePkiCollections(projectId) + queryKey: projectKeys.getProjectPkiCollections(projectId) }); queryClient.invalidateQueries({ queryKey: pkiCollectionKeys.getPkiCollectionById(collectionId) diff --git a/frontend/src/hooks/api/pkiSubscriber/mutations.tsx b/frontend/src/hooks/api/pkiSubscriber/mutations.tsx index b30924f97..57d086780 100644 --- a/frontend/src/hooks/api/pkiSubscriber/mutations.tsx +++ b/frontend/src/hooks/api/pkiSubscriber/mutations.tsx @@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; import { TCreateCertificateResponse } from "../ca/types"; -import { workspaceKeys } from "../workspace/query-keys"; +import { projectKeys } from "../projects/query-keys"; import { pkiSubscriberKeys } from "./queries"; import { TCreatePkiSubscriberDTO, @@ -22,7 +22,7 @@ export const useCreatePkiSubscriber = () => { }, onSuccess: ({ projectId, name }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspacePkiSubscribers(projectId) + queryKey: projectKeys.getProjectPkiSubscribers(projectId) }); queryClient.invalidateQueries({ queryKey: pkiSubscriberKeys.getPkiSubscriber({ @@ -46,7 +46,7 @@ export const useUpdatePkiSubscriber = () => { }, onSuccess: ({ projectId, name }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspacePkiSubscribers(projectId) + queryKey: projectKeys.getProjectPkiSubscribers(projectId) }); queryClient.invalidateQueries({ queryKey: pkiSubscriberKeys.getPkiSubscriber({ @@ -74,7 +74,7 @@ export const useDeletePkiSubscriber = () => { }, onSuccess: ({ name, projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspacePkiSubscribers(projectId) + queryKey: projectKeys.getProjectPkiSubscribers(projectId) }); queryClient.invalidateQueries({ queryKey: pkiSubscriberKeys.getPkiSubscriber({ diff --git a/frontend/src/hooks/api/projectTemplates/types.ts b/frontend/src/hooks/api/projectTemplates/types.ts index f5ff22dff..d58e80f53 100644 --- a/frontend/src/hooks/api/projectTemplates/types.ts +++ b/frontend/src/hooks/api/projectTemplates/types.ts @@ -1,6 +1,6 @@ import { TProjectRole } from "@app/hooks/api/roles/types"; -import { ProjectType } from "../workspace/types"; +import { ProjectType } from "../projects/types"; export type TProjectTemplate = { id: string; diff --git a/frontend/src/hooks/api/workspace/index.tsx b/frontend/src/hooks/api/projects/index.tsx similarity index 89% rename from frontend/src/hooks/api/workspace/index.tsx rename to frontend/src/hooks/api/projects/index.tsx index df2d55dc3..ed8eba815 100644 --- a/frontend/src/hooks/api/workspace/index.tsx +++ b/frontend/src/hooks/api/projects/index.tsx @@ -17,15 +17,14 @@ export { useDeleteWsEnvironment, useGetProjectSshConfig, useGetUpgradeProjectStatus, + useGetUserProjects, useGetUserWorkspaceMemberships, - useGetUserWorkspaces, useGetWorkspaceAuthorizations, useGetWorkspaceById, useGetWorkspaceIdentityMembershipDetails, useGetWorkspaceIdentityMemberships, useGetWorkspaceIndexStatus, useGetWorkspaceIntegrations, - useGetWorkspaceSecrets, useGetWorkspaceUserDetails, useGetWorkspaceUsers, useGetWorkspaceWorkflowIntegrationConfig, @@ -41,13 +40,11 @@ export { useListWorkspaceSshCertificateTemplates, useListWorkspaceSshHostGroups, useListWorkspaceSshHosts, - useNameWorkspaceSecrets, useSearchProjects, - useToggleAutoCapitalization, useUpdateIdentityWorkspaceRole, useUpdateProject, useUpdateUserWorkspaceRole, useUpdateWsEnvironment, useUpgradeProject } from "./queries"; -export { workspaceKeys } from "./query-keys"; +export { projectKeys } from "./query-keys"; diff --git a/frontend/src/hooks/api/workspace/mutations.tsx b/frontend/src/hooks/api/projects/mutations.tsx similarity index 68% rename from frontend/src/hooks/api/workspace/mutations.tsx rename to frontend/src/hooks/api/projects/mutations.tsx index 5cd7e3bbc..e2a80ff53 100644 --- a/frontend/src/hooks/api/workspace/mutations.tsx +++ b/frontend/src/hooks/api/projects/mutations.tsx @@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; import { userKeys } from "../users/query-keys"; -import { workspaceKeys } from "./query-keys"; +import { projectKeys } from "./query-keys"; import { TProjectSshConfig, TUpdateProjectSshConfigDTO, @@ -24,7 +24,7 @@ export const useAddGroupToWorkspace = () => { }) => { const { data: { groupMembership } - } = await apiRequest.post(`/api/v2/workspace/${projectId}/groups/${groupId}`, { + } = await apiRequest.post(`/api/v1/projects/${projectId}/groups/${groupId}`, { role }); @@ -32,7 +32,7 @@ export const useAddGroupToWorkspace = () => { }, onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId) + queryKey: projectKeys.getProjectGroupMemberships(projectId) }); } }); @@ -44,7 +44,7 @@ export const useUpdateGroupWorkspaceRole = () => { mutationFn: async ({ groupId, projectId, roles }: TUpdateWorkspaceGroupRoleDTO) => { const { data: { groupMembership } - } = await apiRequest.patch(`/api/v2/workspace/${projectId}/groups/${groupId}`, { + } = await apiRequest.patch(`/api/v1/projects/${projectId}/groups/${groupId}`, { roles }); @@ -52,10 +52,10 @@ export const useUpdateGroupWorkspaceRole = () => { }, onSuccess: (_, { projectId, groupId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId) + queryKey: projectKeys.getProjectGroupMemberships(projectId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceGroupMembershipDetails(projectId, groupId) + queryKey: projectKeys.getProjectGroupMembershipDetails(projectId, groupId) }); } }); @@ -74,12 +74,12 @@ export const useDeleteGroupFromWorkspace = () => { }) => { const { data: { groupMembership } - } = await apiRequest.delete(`/api/v2/workspace/${projectId}/groups/${groupId}`); + } = await apiRequest.delete(`/api/v1/projects/${projectId}/groups/${groupId}`); return groupMembership; }, onSuccess: (_, { projectId, username }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId) + queryKey: projectKeys.getProjectGroupMemberships(projectId) }); if (username) { @@ -91,25 +91,25 @@ export const useDeleteGroupFromWorkspace = () => { export const useLeaveProject = () => { const queryClient = useQueryClient(); - return useMutation({ - mutationFn: ({ workspaceId }) => { - return apiRequest.delete(`/api/v1/workspace/${workspaceId}/leave`); + return useMutation({ + mutationFn: ({ projectId }) => { + return apiRequest.delete(`/api/v1/projects/${projectId}/leave`); }, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); + queryClient.invalidateQueries({ queryKey: projectKeys.getAllUserProjects() }); } }); }; export const useMigrateProjectToV3 = () => { const queryClient = useQueryClient(); - return useMutation({ - mutationFn: ({ workspaceId }) => { - return apiRequest.post(`/api/v1/workspace/${workspaceId}/migrate-v3`); + return useMutation({ + mutationFn: ({ projectId }) => { + return apiRequest.post(`/api/v1/projects/${projectId}/migrate-v3`); }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); @@ -118,7 +118,7 @@ export const useMigrateProjectToV3 = () => { export const useRequestProjectAccess = () => { return useMutation({ mutationFn: ({ projectId, comment }) => { - return apiRequest.post(`/api/v1/workspace/${projectId}/project-access`, { + return apiRequest.post(`/api/v1/projects/${projectId}/project-access`, { comment }); } @@ -129,14 +129,14 @@ export const useUpdateProjectSshConfig = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ projectId, defaultUserSshCaId, defaultHostSshCaId }) => { - return apiRequest.patch(`/api/v1/workspace/${projectId}/ssh-config`, { + return apiRequest.patch(`/api/v1/projects/${projectId}/ssh-config`, { defaultUserSshCaId, defaultHostSshCaId }); }, onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getProjectSshConfig(projectId) + queryKey: projectKeys.getProjectSshConfig(projectId) }); } }); diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/projects/queries.tsx similarity index 55% rename from frontend/src/hooks/api/workspace/queries.tsx rename to frontend/src/hooks/api/projects/queries.tsx index 3c7a6d30c..0445d5984 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/projects/queries.tsx @@ -15,7 +15,6 @@ import { TIntegration } from "../integrations/types"; import { TPkiAlert } from "../pkiAlerts/types"; import { TPkiCollection } from "../pkiCollections/types"; import { TPkiSubscriber } from "../pkiSubscriber/types"; -import { EncryptedSecret } from "../secrets/types"; import { TSshCertificate, TSshCertificateAuthority } from "../sshCa/types"; import { TSshCertificateTemplate } from "../sshCertificateTemplates/types"; import { TSshHost } from "../sshHost/types"; @@ -26,42 +25,36 @@ import { ProjectWorkflowIntegrationConfig, WorkflowIntegrationPlatform } from "../workflowIntegrations/types"; -import { workspaceKeys } from "./query-keys"; +import { projectKeys } from "./query-keys"; import { CreateEnvironmentDTO, CreateWorkspaceDTO, DeleteEnvironmentDTO, DeleteWorkspaceDTO, - NameWorkspaceSecretsDTO, + Project, + ProjectEnv, ProjectIdentityOrderBy, ProjectType, TGetUpgradeProjectStatusDTO, TListProjectIdentitiesDTO, - ToggleAutoCapitalizationDTO, - ToggleDeleteProjectProtectionDTO, TProjectSshConfig, TSearchProjectsDTO, TUpdateWorkspaceIdentityRoleDTO, TUpdateWorkspaceUserRoleDTO, UpdateAuditLogsRetentionDTO, UpdateEnvironmentDTO, - UpdatePitVersionLimitDTO, - UpdateProjectDTO, - Workspace, - WorkspaceEnv + UpdateProjectDTO } from "./types"; -export const fetchWorkspaceById = async (workspaceId: string) => { - const { data } = await apiRequest.get<{ workspace: Workspace }>( - `/api/v1/workspace/${workspaceId}` - ); +export const fetchProjectById = async (projectId: string) => { + const { data } = await apiRequest.get<{ project: Project }>(`/api/v1/projects/${projectId}`); - return data.workspace; + return data.project; }; -const fetchWorkspaceIndexStatus = async (workspaceId: string) => { +const fetchWorkspaceIndexStatus = async (projectId: string) => { const { data } = await apiRequest.get( - `/api/v3/workspaces/${workspaceId}/secrets/blind-index-status` + `/api/v3/projects/${projectId}/secrets/blind-index-status` ); return data; @@ -69,34 +62,24 @@ const fetchWorkspaceIndexStatus = async (workspaceId: string) => { const fetchProjectUpgradeStatus = async (projectId: string) => { const { data } = await apiRequest.get<{ status: string }>( - `/api/v2/workspace/${projectId}/upgrade/status` + `/api/v1/projects/${projectId}/upgrade/status` ); return data; }; -export const fetchWorkspaceSecrets = async (workspaceId: string) => { - const { - data: { secrets } - } = await apiRequest.get<{ secrets: EncryptedSecret[] }>( - `/api/v3/workspaces/${workspaceId}/secrets` - ); - - return secrets; -}; - export const useUpgradeProject = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: ({ projectId, privateKey }) => { - return apiRequest.post(`/api/v2/workspace/${projectId}/upgrade`, { + return apiRequest.post(`/api/v1/projects/${projectId}/upgrade`, { userPrivateKey: privateKey }); }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); @@ -108,7 +91,7 @@ export const useGetUpgradeProjectStatus = ({ refetchInterval }: TGetUpgradeProjectStatusDTO) => { return useQuery({ - queryKey: workspaceKeys.getProjectUpgradeStatus(projectId), + queryKey: projectKeys.getProjectUpgradeStatus(projectId), queryFn: () => fetchProjectUpgradeStatus(projectId), enabled, refetchInterval @@ -116,44 +99,36 @@ export const useGetUpgradeProjectStatus = ({ }; const fetchUserWorkspaces = async (includeRoles?: boolean, type?: ProjectType | "all") => { - const { data } = await apiRequest.get<{ workspaces: Workspace[] }>("/api/v1/workspace", { + const { data } = await apiRequest.get<{ projects: Project[] }>("/api/v1/projects", { params: { includeRoles, type } }); - return data.workspaces; + return data.projects; }; -export const useGetWorkspaceIndexStatus = (workspaceId: string) => { +export const useGetWorkspaceIndexStatus = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceIndexStatus(workspaceId), - queryFn: () => fetchWorkspaceIndexStatus(workspaceId), - enabled: true - }); -}; - -export const useGetWorkspaceSecrets = (workspaceId: string) => { - return useQuery({ - queryKey: workspaceKeys.getWorkspaceSecrets(workspaceId), - queryFn: () => fetchWorkspaceSecrets(workspaceId), + queryKey: projectKeys.getProjectIndexStatus(projectId), + queryFn: () => fetchWorkspaceIndexStatus(projectId), enabled: true }); }; export const useGetWorkspaceById = ( - workspaceId: string, + projectId: string, dto?: { refetchInterval?: number | false } ) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceById(workspaceId), - queryFn: () => fetchWorkspaceById(workspaceId), - enabled: Boolean(workspaceId), + queryKey: projectKeys.getProjectById(projectId), + queryFn: () => fetchProjectById(projectId), + enabled: Boolean(projectId), refetchInterval: dto?.refetchInterval }); }; -export const useGetUserWorkspaces = ({ +export const useGetUserProjects = ({ includeRoles, options = {} }: { @@ -161,19 +136,19 @@ export const useGetUserWorkspaces = ({ options?: { enabled?: boolean }; } = {}) => useQuery({ - queryKey: workspaceKeys.getAllUserWorkspace(), + queryKey: projectKeys.getAllUserProjects(), queryFn: () => fetchUserWorkspaces(includeRoles), ...options }); export const useSearchProjects = ({ options, ...dto }: TSearchProjectsDTO) => useQuery({ - queryKey: workspaceKeys.searchWorkspace(dto), + queryKey: projectKeys.searchProject(dto), queryFn: async () => { const { data } = await apiRequest.post<{ - projects: (Workspace & { isMember: boolean })[]; + projects: (Project & { isMember: boolean })[]; totalCount: number; - }>("/api/v1/workspace/search", dto); + }>("/api/v1/projects/search", dto); return data; }, @@ -181,81 +156,65 @@ export const useSearchProjects = ({ options, ...dto }: TSearchProjectsDTO) => }); const fetchUserWorkspaceMemberships = async (orgId: string) => { - const { data } = await apiRequest.get>( - `/api/v1/organization/${orgId}/workspace-memberships` + const { data } = await apiRequest.get>( + `/api/v1/organization/${orgId}/project-memberships` ); return data; }; -// to get all userids in an org with the workspace they are part of +// to get all userids in an org with the project they are part of export const useGetUserWorkspaceMemberships = (orgId: string) => useQuery({ - queryKey: workspaceKeys.getWorkspaceMemberships(orgId), + queryKey: projectKeys.getProjectMemberships(orgId), queryFn: () => fetchUserWorkspaceMemberships(orgId), enabled: Boolean(orgId) }); -export const useNameWorkspaceSecrets = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ workspaceId, secretsToUpdate }) => - apiRequest.post(`/api/v3/workspaces/${workspaceId}/secrets/names`, { - secretsToUpdate - }), - onSuccess: (_, variables) => { - queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIndexStatus(variables.workspaceId) - }); - } - }); -}; - -const fetchWorkspaceAuthorization = async (workspaceId: string) => { +const fetchWorkspaceAuthorization = async (projectId: string) => { const { data } = await apiRequest.get<{ authorizations: IntegrationAuth[] }>( - `/api/v1/workspace/${workspaceId}/authorizations` + `/api/v1/projects/${projectId}/authorizations` ); return data.authorizations; }; export const useGetWorkspaceAuthorizations = ( - workspaceId: string, + projectId: string, select?: (data: IntegrationAuth[]) => TData ) => useQuery({ - queryKey: workspaceKeys.getWorkspaceAuthorization(workspaceId), - queryFn: () => fetchWorkspaceAuthorization(workspaceId), - enabled: Boolean(workspaceId), + queryKey: projectKeys.getProjectAuthorization(projectId), + queryFn: () => fetchWorkspaceAuthorization(projectId), + enabled: Boolean(projectId), select }); -export const fetchWorkspaceIntegrations = async (workspaceId: string) => { +export const fetchWorkspaceIntegrations = async (projectId: string) => { const { data } = await apiRequest.get<{ integrations: TIntegration[] }>( - `/api/v1/workspace/${workspaceId}/integrations` + `/api/v1/projects/${projectId}/integrations` ); return data.integrations; }; -export const useGetWorkspaceIntegrations = (workspaceId: string) => +export const useGetWorkspaceIntegrations = (projectId: string) => useQuery({ - queryKey: workspaceKeys.getWorkspaceIntegrations(workspaceId), - queryFn: () => fetchWorkspaceIntegrations(workspaceId), - enabled: Boolean(workspaceId), + queryKey: projectKeys.getProjectIntegrations(projectId), + queryFn: () => fetchWorkspaceIntegrations(projectId), + enabled: Boolean(projectId), refetchInterval: 4000 }); export const createWorkspace = ( dto: CreateWorkspaceDTO -): Promise<{ data: { project: Workspace } }> => { - return apiRequest.post("/api/v2/workspace", dto); +): Promise<{ data: { project: Project } }> => { + return apiRequest.post("/api/v1/projects", dto); }; export const useCreateWorkspace = () => { const queryClient = useQueryClient(); - return useMutation<{ data: { project: Workspace } }, object, CreateWorkspaceDTO>({ + return useMutation<{ data: { project: Project } }, object, CreateWorkspaceDTO>({ mutationFn: async ({ projectName, projectDescription, kmsKeyId, template, type }) => createWorkspace({ projectName, @@ -266,7 +225,7 @@ export const useCreateWorkspace = () => { }), onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); @@ -275,85 +234,37 @@ export const useCreateWorkspace = () => { export const useUpdateProject = () => { const queryClient = useQueryClient(); - return useMutation({ + return useMutation({ mutationFn: async ({ - projectID, + projectId: projectID, newProjectName, + hasDeleteProtection, newProjectDescription, newSlug, secretSharing, showSnapshotsLegacy, - secretDetectionIgnoreValues + secretDetectionIgnoreValues, + autoCapitalization, + pitVersionLimit }) => { - const { data } = await apiRequest.patch<{ workspace: Workspace }>( - `/api/v1/workspace/${projectID}`, + const { data } = await apiRequest.patch<{ project: Project }>( + `/api/v1/projects/${projectID}`, { name: newProjectName, description: newProjectDescription, slug: newSlug, secretSharing, showSnapshotsLegacy, - secretDetectionIgnoreValues + secretDetectionIgnoreValues, + autoCapitalization, + pitVersionLimit, + hasDeleteProtection } ); - return data.workspace; + return data.project; }, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); - } - }); -}; - -export const useToggleAutoCapitalization = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ workspaceID, state }) => { - const { data } = await apiRequest.post<{ workspace: Workspace }>( - `/api/v1/workspace/${workspaceID}/auto-capitalization`, - { - autoCapitalization: state - } - ); - return data.workspace; - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); - } - }); -}; - -export const useToggleDeleteProjectProtection = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ workspaceID, state }) => { - const { data } = await apiRequest.post<{ workspace: Workspace }>( - `/api/v1/workspace/${workspaceID}/delete-protection`, - { - hasDeleteProtection: state - } - ); - return data.workspace; - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); - } - }); -}; - -export const useUpdateWorkspaceVersionLimit = () => { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ projectSlug, pitVersionLimit }) => { - const { data } = await apiRequest.put(`/api/v1/workspace/${projectSlug}/version-limit`, { - pitVersionLimit - }); - return data.workspace; - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); + queryClient.invalidateQueries({ queryKey: projectKeys.getAllUserProjects() }); } }); }; @@ -361,18 +272,18 @@ export const useUpdateWorkspaceVersionLimit = () => { export const useUpdateWorkspaceAuditLogsRetention = () => { const queryClient = useQueryClient(); - return useMutation({ + return useMutation({ mutationFn: async ({ projectSlug, auditLogsRetentionDays }) => { const { data } = await apiRequest.put( - `/api/v1/workspace/${projectSlug}/audit-logs-retention`, + `/api/v1/projects/${projectSlug}/audit-logs-retention`, { auditLogsRetentionDays } ); - return data.workspace; + return data.project; }, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); + queryClient.invalidateQueries({ queryKey: projectKeys.getAllUserProjects() }); } }); }; @@ -380,13 +291,13 @@ export const useUpdateWorkspaceAuditLogsRetention = () => { export const useDeleteWorkspace = () => { const queryClient = useQueryClient(); - return useMutation({ - mutationFn: async ({ workspaceID }) => { - const { data } = await apiRequest.delete(`/api/v1/workspace/${workspaceID}`); - return data.workspace; + return useMutation({ + mutationFn: async ({ projectID }) => { + const { data } = await apiRequest.delete(`/api/v1/projects/${projectID}`); + return data.project; }, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); + queryClient.invalidateQueries({ queryKey: projectKeys.getAllUserProjects() }); queryClient.invalidateQueries({ queryKey: ["org-admin-projects"] }); @@ -397,10 +308,10 @@ export const useDeleteWorkspace = () => { export const useCreateWsEnvironment = () => { const queryClient = useQueryClient(); - return useMutation({ - mutationFn: async ({ workspaceId, name, slug }) => { - const { data } = await apiRequest.post<{ environment: WorkspaceEnv }>( - `/api/v1/workspace/${workspaceId}/environments`, + return useMutation({ + mutationFn: async ({ projectId, name, slug }) => { + const { data } = await apiRequest.post<{ environment: ProjectEnv }>( + `/api/v1/projects/${projectId}/environments`, { name, slug @@ -410,7 +321,7 @@ export const useCreateWsEnvironment = () => { }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); @@ -420,8 +331,8 @@ export const useUpdateWsEnvironment = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ workspaceId, id, name, slug, position }) => { - return apiRequest.patch(`/api/v1/workspace/${workspaceId}/environments/${id}`, { + mutationFn: ({ projectId, id, name, slug, position }) => { + return apiRequest.patch(`/api/v1/projects/${projectId}/environments/${id}`, { name, slug, position @@ -429,7 +340,7 @@ export const useUpdateWsEnvironment = () => { }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); @@ -439,57 +350,54 @@ export const useDeleteWsEnvironment = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ id, workspaceId }) => { - return apiRequest.delete(`/api/v1/workspace/${workspaceId}/environments/${id}`); + mutationFn: ({ id, projectId }) => { + return apiRequest.delete(`/api/v1/projects/${projectId}/environments/${id}`); }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }); }; export const useGetWorkspaceUsers = ( - workspaceId: string, + projectId: string, includeGroupMembers?: boolean, roles?: string[] ) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceUsers(workspaceId, includeGroupMembers, roles), + queryKey: projectKeys.getProjectUsers(projectId, includeGroupMembers, roles), queryFn: async () => { const { data: { users } - } = await apiRequest.get<{ users: TWorkspaceUser[] }>( - `/api/v1/workspace/${workspaceId}/users`, - { - params: { - includeGroupMembers, - roles: - roles && roles.length > 0 - ? roles.map((role) => encodeURIComponent(role)).join(",") - : undefined - } + } = await apiRequest.get<{ users: TWorkspaceUser[] }>(`/api/v1/projects/${projectId}/users`, { + params: { + includeGroupMembers, + roles: + roles && roles.length > 0 + ? roles.map((role) => encodeURIComponent(role)).join(",") + : undefined } - ); + }); return users; }, enabled: true }); }; -export const useGetWorkspaceUserDetails = (workspaceId: string, membershipId: string) => { +export const useGetWorkspaceUserDetails = (projectId: string, membershipId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceUserDetails(workspaceId, membershipId), + queryKey: projectKeys.getProjectUserDetails(projectId, membershipId), queryFn: async () => { const { data: { membership } } = await apiRequest.get<{ membership: TWorkspaceUser }>( - `/api/v1/workspace/${workspaceId}/memberships/${membershipId}` + `/api/v1/projects/${projectId}/memberships/${membershipId}` ); return membership; }, - enabled: Boolean(workspaceId) && Boolean(membershipId) + enabled: Boolean(projectId) && Boolean(membershipId) }); }; @@ -499,21 +407,21 @@ export const useDeleteUserFromWorkspace = () => { return useMutation({ mutationFn: async ({ usernames, - workspaceId + projectId }: { - workspaceId: string; + projectId: string; usernames: string[]; orgId: string; }) => { const { data: { deletedMembership } - } = await apiRequest.delete(`/api/v2/workspace/${workspaceId}/memberships`, { + } = await apiRequest.delete(`/api/v1/projects/${projectId}/memberships`, { data: { usernames } }); return deletedMembership; }, - onSuccess: (_, { orgId, workspaceId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceUsers(workspaceId) }); + onSuccess: (_, { orgId, projectId }) => { + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectUsers(projectId) }); queryClient.invalidateQueries({ queryKey: userKeys.allOrgMembershipProjectMemberships(orgId) }); @@ -524,21 +432,21 @@ export const useDeleteUserFromWorkspace = () => { export const useUpdateUserWorkspaceRole = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ membershipId, roles, workspaceId }: TUpdateWorkspaceUserRoleDTO) => { + mutationFn: async ({ membershipId, roles, projectId }: TUpdateWorkspaceUserRoleDTO) => { const { data: { membership } } = await apiRequest.patch<{ membership: { projectId: string } }>( - `/api/v1/workspace/${workspaceId}/memberships/${membershipId}`, + `/api/v1/projects/${projectId}/memberships/${membershipId}`, { roles } ); return membership; }, - onSuccess: (_, { workspaceId, membershipId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceUsers(workspaceId) }); + onSuccess: (_, { projectId, membershipId }) => { + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectUsers(projectId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceUserDetails(workspaceId, membershipId) + queryKey: projectKeys.getProjectUserDetails(projectId, membershipId) }); } }); @@ -549,17 +457,17 @@ export const useAddIdentityToWorkspace = () => { return useMutation({ mutationFn: async ({ identityId, - workspaceId, + projectId, role }: { identityId: string; - workspaceId: string; + projectId: string; role?: string; }) => { const { data: { identityMembership } } = await apiRequest.post( - `/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`, + `/api/v1/projects/${projectId}/identity-memberships/${identityId}`, { role } @@ -567,9 +475,9 @@ export const useAddIdentityToWorkspace = () => { return identityMembership; }, - onSuccess: (_, { identityId, workspaceId }) => { + onSuccess: (_, { identityId, projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIdentityMemberships(workspaceId) + queryKey: projectKeys.getProjectIdentityMemberships(projectId) }); queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityProjectMemberships(identityId) @@ -581,11 +489,11 @@ export const useAddIdentityToWorkspace = () => { export const useUpdateIdentityWorkspaceRole = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ identityId, workspaceId, roles }: TUpdateWorkspaceIdentityRoleDTO) => { + mutationFn: async ({ identityId, projectId, roles }: TUpdateWorkspaceIdentityRoleDTO) => { const { data: { identityMembership } } = await apiRequest.patch( - `/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}`, + `/api/v1/projects/${projectId}/identity-memberships/${identityId}`, { roles } @@ -593,15 +501,15 @@ export const useUpdateIdentityWorkspaceRole = () => { return identityMembership; }, - onSuccess: (_, { identityId, workspaceId }) => { + onSuccess: (_, { identityId, projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIdentityMemberships(workspaceId) + queryKey: projectKeys.getProjectIdentityMemberships(projectId) }); queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityProjectMemberships(identityId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIdentityMembershipDetails(workspaceId, identityId) + queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId) }); } }); @@ -610,23 +518,17 @@ export const useUpdateIdentityWorkspaceRole = () => { export const useDeleteIdentityFromWorkspace = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ - identityId, - workspaceId - }: { - identityId: string; - workspaceId: string; - }) => { + mutationFn: async ({ identityId, projectId }: { identityId: string; projectId: string }) => { const { data: { identityMembership } } = await apiRequest.delete( - `/api/v2/workspace/${workspaceId}/identity-memberships/${identityId}` + `/api/v1/projects/${projectId}/identity-memberships/${identityId}` ); return identityMembership; }, - onSuccess: (_, { identityId, workspaceId }) => { + onSuccess: (_, { identityId, projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceIdentityMemberships(workspaceId) + queryKey: projectKeys.getProjectIdentityMemberships(projectId) }); queryClient.invalidateQueries({ queryKey: identitiesKeys.getIdentityProjectMemberships(identityId) @@ -637,7 +539,7 @@ export const useDeleteIdentityFromWorkspace = () => { export const useGetWorkspaceIdentityMemberships = ( { - workspaceId, + projectId, offset = 0, limit = 100, orderBy = ProjectIdentityOrderBy.Name, @@ -649,14 +551,14 @@ export const useGetWorkspaceIdentityMemberships = ( TProjectIdentitiesList, unknown, TProjectIdentitiesList, - ReturnType + ReturnType >, "queryKey" | "queryFn" > ) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceIdentityMembershipsWithParams({ - workspaceId, + queryKey: projectKeys.getProjectIdentityMembershipsWithParams({ + projectId, offset, limit, orderBy, @@ -673,7 +575,7 @@ export const useGetWorkspaceIdentityMemberships = ( }); const { data } = await apiRequest.get( - `/api/v2/workspace/${workspaceId}/identity-memberships`, + `/api/v1/projects/${projectId}/identity-memberships`, { params } ); return data; @@ -686,12 +588,12 @@ export const useGetWorkspaceIdentityMemberships = ( export const useGetWorkspaceIdentityMembershipDetails = (projectId: string, identityId: string) => { return useQuery({ enabled: Boolean(projectId && identityId), - queryKey: workspaceKeys.getWorkspaceIdentityMembershipDetails(projectId, identityId), + queryKey: projectKeys.getProjectIdentityMembershipDetails(projectId, identityId), queryFn: async () => { const { data: { identityMembership } } = await apiRequest.get<{ identityMembership: IdentityMembership }>( - `/api/v2/workspace/${projectId}/identity-memberships/${identityId}` + `/api/v1/projects/${projectId}/identity-memberships/${identityId}` ); return identityMembership; } @@ -701,12 +603,12 @@ export const useGetWorkspaceIdentityMembershipDetails = (projectId: string, iden export const useGetWorkspaceGroupMembershipDetails = (projectId: string, groupId: string) => { return useQuery({ enabled: Boolean(projectId && groupId), - queryKey: workspaceKeys.getWorkspaceGroupMembershipDetails(projectId, groupId), + queryKey: projectKeys.getProjectGroupMembershipDetails(projectId, groupId), queryFn: async () => { const { data: { groupMembership } } = await apiRequest.get<{ groupMembership: TGroupMembership }>( - `/api/v2/workspace/${projectId}/groups/${groupId}` + `/api/v1/projects/${projectId}/groups/${groupId}` ); return groupMembership; } @@ -715,12 +617,12 @@ export const useGetWorkspaceGroupMembershipDetails = (projectId: string, groupId export const useListWorkspaceGroups = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectId), + queryKey: projectKeys.getProjectGroupMemberships(projectId), queryFn: async () => { const { data: { groupMemberships } } = await apiRequest.get<{ groupMemberships: TGroupMembership[] }>( - `/api/v2/workspace/${projectId}/groups` + `/api/v1/projects/${projectId}/groups` ); return groupMemberships; }, @@ -729,15 +631,15 @@ export const useListWorkspaceGroups = (projectId: string) => { }; export const useListWorkspaceCas = ({ - projectSlug, + projectId, status }: { - projectSlug: string; + projectId: string; status?: CaStatus; }) => { return useQuery({ - queryKey: workspaceKeys.specificWorkspaceCas({ - projectSlug, + queryKey: projectKeys.specificProjectCas({ + projectId, status }), queryFn: async () => { @@ -748,29 +650,29 @@ export const useListWorkspaceCas = ({ const { data: { cas } } = await apiRequest.get<{ cas: TCertificateAuthority[] }>( - `/api/v2/workspace/${projectSlug}/cas`, + `/api/v1/projects/${projectId}/cas`, { params } ); return cas; }, - enabled: Boolean(projectSlug) + enabled: Boolean(projectId) }); }; export const useListWorkspaceCertificates = ({ - projectSlug, + projectId, offset, limit }: { - projectSlug: string; + projectId: string; offset: number; limit: number; }) => { return useQuery({ - queryKey: workspaceKeys.specificWorkspaceCertificates({ - slug: projectSlug, + queryKey: projectKeys.specificProjectCertificates({ + projectId, offset, limit }), @@ -783,7 +685,7 @@ export const useListWorkspaceCertificates = ({ const { data: { certificates, totalCount } } = await apiRequest.get<{ certificates: TCertificate[]; totalCount: number }>( - `/api/v2/workspace/${projectSlug}/certificates`, + `/api/v1/projects/${projectId}/certificates`, { params } @@ -791,55 +693,53 @@ export const useListWorkspaceCertificates = ({ return { certificates, totalCount }; }, - enabled: Boolean(projectSlug) + enabled: Boolean(projectId) }); }; -export const useListWorkspacePkiAlerts = ({ workspaceId }: { workspaceId: string }) => { +export const useListWorkspacePkiAlerts = ({ projectId }: { projectId: string }) => { return useQuery({ - queryKey: workspaceKeys.getWorkspacePkiAlerts(workspaceId), + queryKey: projectKeys.getProjectPkiAlerts(projectId), queryFn: async () => { const { data: { alerts } - } = await apiRequest.get<{ alerts: TPkiAlert[] }>( - `/api/v2/workspace/${workspaceId}/pki-alerts` - ); + } = await apiRequest.get<{ alerts: TPkiAlert[] }>(`/api/v1/projects/${projectId}/pki-alerts`); return { alerts }; }, - enabled: Boolean(workspaceId) + enabled: Boolean(projectId) }); }; -export const useListWorkspacePkiCollections = ({ workspaceId }: { workspaceId: string }) => { +export const useListWorkspacePkiCollections = ({ projectId }: { projectId: string }) => { return useQuery({ - queryKey: workspaceKeys.getWorkspacePkiCollections(workspaceId), + queryKey: projectKeys.getProjectPkiCollections(projectId), queryFn: async () => { const { data: { collections } } = await apiRequest.get<{ collections: TPkiCollection[] }>( - `/api/v2/workspace/${workspaceId}/pki-collections` + `/api/v1/projects/${projectId}/pki-collections` ); return { collections }; }, - enabled: Boolean(workspaceId) + enabled: Boolean(projectId) }); }; -export const useListWorkspaceCertificateTemplates = ({ workspaceId }: { workspaceId: string }) => { +export const useListWorkspaceCertificateTemplates = ({ projectId }: { projectId: string }) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceCertificateTemplates(workspaceId), + queryKey: projectKeys.getProjectCertificateTemplates(projectId), queryFn: async () => { const { data: { certificateTemplates } } = await apiRequest.get<{ certificateTemplates: TCertificateTemplate[] }>( - `/api/v2/workspace/${workspaceId}/certificate-templates` + `/api/v1/projects/${projectId}/certificate-templates` ); return { certificateTemplates }; }, - enabled: Boolean(workspaceId) + enabled: Boolean(projectId) }); }; @@ -853,7 +753,7 @@ export const useListWorkspaceSshCertificates = ({ projectId: string; }) => { return useQuery({ - queryKey: workspaceKeys.specificWorkspaceSshCertificates({ + queryKey: projectKeys.specificProjectSshCertificates({ offset, limit, projectId @@ -867,7 +767,7 @@ export const useListWorkspaceSshCertificates = ({ const { data } = await apiRequest.get<{ certificates: TSshCertificate[]; totalCount: number; - }>(`/api/v2/workspace/${projectId}/ssh-certificates`, { + }>(`/api/v1/projects/${projectId}/ssh-certificates`, { params }); return data; @@ -878,12 +778,12 @@ export const useListWorkspaceSshCertificates = ({ export const useListWorkspaceSshCas = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceSshCas(projectId), + queryKey: projectKeys.getProjectSshCas(projectId), queryFn: async () => { const { data: { cas } } = await apiRequest.get<{ cas: Omit[] }>( - `/api/v2/workspace/${projectId}/ssh-cas` + `/api/v1/projects/${projectId}/ssh-cas` ); return cas; }, @@ -893,11 +793,11 @@ export const useListWorkspaceSshCas = (projectId: string) => { export const useListWorkspaceSshHosts = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceSshHosts(projectId), + queryKey: projectKeys.getProjectSshHosts(projectId), queryFn: async () => { const { data: { hosts } - } = await apiRequest.get<{ hosts: TSshHost[] }>(`/api/v2/workspace/${projectId}/ssh-hosts`); + } = await apiRequest.get<{ hosts: TSshHost[] }>(`/api/v1/projects/${projectId}/ssh-hosts`); return hosts; }, enabled: Boolean(projectId) @@ -906,12 +806,12 @@ export const useListWorkspaceSshHosts = (projectId: string) => { export const useListWorkspacePkiSubscribers = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspacePkiSubscribers(projectId), + queryKey: projectKeys.getProjectPkiSubscribers(projectId), queryFn: async () => { const { data: { subscribers } } = await apiRequest.get<{ subscribers: TPkiSubscriber[] }>( - `/api/v2/workspace/${projectId}/pki-subscribers` + `/api/v1/projects/${projectId}/pki-subscribers` ); return subscribers; }, @@ -921,12 +821,12 @@ export const useListWorkspacePkiSubscribers = (projectId: string) => { export const useListWorkspaceSshHostGroups = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId), + queryKey: projectKeys.getProjectSshHostGroups(projectId), queryFn: async () => { const { data: { groups } } = await apiRequest.get<{ groups: (TSshHostGroup & { hostCount: number })[] }>( - `/api/v2/workspace/${projectId}/ssh-host-groups` + `/api/v1/projects/${projectId}/ssh-host-groups` ); return groups; }, @@ -936,10 +836,10 @@ export const useListWorkspaceSshHostGroups = (projectId: string) => { export const useListWorkspaceSshCertificateTemplates = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceSshCertificateTemplates(projectId), + queryKey: projectKeys.getProjectSshCertificateTemplates(projectId), queryFn: async () => { const { data } = await apiRequest.get<{ certificateTemplates: TSshCertificateTemplate[] }>( - `/api/v2/workspace/${projectId}/ssh-certificate-templates` + `/api/v1/projects/${projectId}/ssh-certificate-templates` ); return data; }, @@ -948,18 +848,18 @@ export const useListWorkspaceSshCertificateTemplates = (projectId: string) => { }; export const useGetWorkspaceWorkflowIntegrationConfig = ({ - workspaceId, + projectId, integration }: { - workspaceId: string; + projectId: string; integration: WorkflowIntegrationPlatform; }) => { return useQuery({ - queryKey: workspaceKeys.getWorkspaceWorkflowIntegrationConfig(workspaceId, integration), + queryKey: projectKeys.getProjectWorkflowIntegrationConfig(projectId, integration), queryFn: async () => { const { data } = await apiRequest .get( - `/api/v1/workspace/${workspaceId}/workflow-integration-config/${integration}` + `/api/v1/projects/${projectId}/workflow-integration-config/${integration}` ) .catch((err) => { if (err.response.status === 404) { @@ -971,16 +871,16 @@ export const useGetWorkspaceWorkflowIntegrationConfig = ({ return data; }, - enabled: Boolean(workspaceId) + enabled: Boolean(projectId) }); }; export const useGetProjectSshConfig = (projectId: string) => { return useQuery({ - queryKey: workspaceKeys.getProjectSshConfig(projectId), + queryKey: projectKeys.getProjectSshConfig(projectId), queryFn: async () => { const { data } = await apiRequest.get( - `/api/v1/workspace/${projectId}/ssh-config` + `/api/v1/projects/${projectId}/ssh-config` ); return data; diff --git a/frontend/src/hooks/api/projects/query-keys.tsx b/frontend/src/hooks/api/projects/query-keys.tsx new file mode 100644 index 000000000..51e3db71c --- /dev/null +++ b/frontend/src/hooks/api/projects/query-keys.tsx @@ -0,0 +1,77 @@ +import type { CaStatus } from "../ca"; +import { WorkflowIntegrationPlatform } from "../workflowIntegrations/types"; +import { TListProjectIdentitiesDTO, TSearchProjectsDTO } from "./types"; + +export const projectKeys = { + getProjectById: (projectId: string) => ["projects", { projectId }] as const, + getProjectSecrets: (projectId: string) => [{ projectId }, "project-secrets"] as const, + getProjectIndexStatus: (projectId: string) => [{ projectId }, "project-index-status"] as const, + getProjectUpgradeStatus: (projectId: string) => [{ projectId }, "project-upgrade-status"], + getProjectMemberships: (orgId: string) => [{ orgId }, "project-memberships"], + getProjectAuthorization: (projectId: string) => [{ projectId }, "project-authorizations"], + getProjectIntegrations: (projectId: string) => [{ projectId }, "project-integrations"], + getAllUserProjects: () => ["projects"] as const, + getProjectAuditLogs: (projectId: string) => [{ projectId }, "project-audit-logs"] as const, + getProjectUsers: ( + projectId: string, + includeGroupMembers: boolean = false, + roles: string[] = [] + ) => [{ projectId, includeGroupMembers, roles }, "project-users"] as const, + getProjectUserDetails: (projectId: string, membershipId: string) => + [{ projectId, membershipId }, "project-user-details"] as const, + getProjectIdentityMemberships: (projectId: string) => + [{ projectId }, "project-identity-memberships"] as const, + getProjectIdentityMembershipDetails: (projectId: string, identityId: string) => + [{ projectId, identityId }, "project-identity-membership-details"] as const, + // allows invalidation using above key without knowing params + getProjectIdentityMembershipsWithParams: ({ projectId, ...params }: TListProjectIdentitiesDTO) => + [...projectKeys.getProjectIdentityMemberships(projectId), params] as const, + searchProject: (dto: TSearchProjectsDTO) => ["search-projects", dto] as const, + getProjectGroupMemberships: (projectId: string) => [{ projectId }, "project-groups"] as const, + getProjectGroupMembershipDetails: (projectId: string, groupId: string) => + [{ projectId, groupId }, "project-group-membership-details"] as const, + getProjectCas: ({ projectId }: { projectId: string }) => [{ projectId }, "project-cas"] as const, + specificProjectCas: ({ projectId, status }: { projectId: string; status?: CaStatus }) => + [...projectKeys.getProjectCas({ projectId }), { status }] as const, + allProjectCertificates: () => ["project-certificates"] as const, + forProjectCertificates: (projectId: string) => + [...projectKeys.allProjectCertificates(), projectId] as const, + specificProjectCertificates: ({ + projectId, + offset, + limit + }: { + projectId: string; + offset: number; + limit: number; + }) => [...projectKeys.forProjectCertificates(projectId), { offset, limit }] as const, + getProjectPkiAlerts: (projectId: string) => [{ projectId }, "project-pki-alerts"] as const, + getProjectPkiSubscribers: (projectId: string) => + [{ projectId }, "project-pki-subscribers"] as const, + getProjectPkiCollections: (projectId: string) => + [{ projectId }, "project-pki-collections"] as const, + getProjectCertificateTemplates: (projectId: string) => + [{ projectId }, "project-certificate-templates"] as const, + getProjectWorkflowIntegrationConfig: ( + projectId: string, + integration: WorkflowIntegrationPlatform + ) => [{ projectId, integration }, "project-workflow-integration-config"] as const, + getProjectSshCas: (projectId: string) => [{ projectId }, "project-ssh-cas"] as const, + allProjectSshCertificates: (projectId: string) => + [{ projectId }, "project-ssh-certificates"] as const, + getProjectSshHosts: (projectId: string) => [{ projectId }, "project-ssh-hosts"] as const, + getProjectSshHostGroups: (projectId: string) => + [{ projectId }, "project-ssh-host-groups"] as const, + specificProjectSshCertificates: ({ + offset, + limit, + projectId + }: { + offset: number; + limit: number; + projectId: string; + }) => [...projectKeys.allProjectSshCertificates(projectId), { offset, limit }] as const, + getProjectSshCertificateTemplates: (projectId: string) => + [{ projectId }, "project-ssh-certificate-templates"] as const, + getProjectSshConfig: (projectId: string) => [{ projectId }, "project-ssh-config"] as const +}; diff --git a/frontend/src/hooks/api/workspace/types.ts b/frontend/src/hooks/api/projects/types.ts similarity index 85% rename from frontend/src/hooks/api/workspace/types.ts rename to frontend/src/hooks/api/projects/types.ts index e87bc439e..59b242d05 100644 --- a/frontend/src/hooks/api/workspace/types.ts +++ b/frontend/src/hooks/api/projects/types.ts @@ -20,7 +20,7 @@ export enum ProjectUserMembershipTemporaryMode { Relative = "relative" } -export type Workspace = { +export type Project = { __v: number; id: string; name: string; @@ -31,7 +31,7 @@ export type Workspace = { upgradeStatus: string | null; updatedAt: string; autoCapitalization: boolean; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; pitVersionLimit: number; auditLogsRetentionDays: number; slug: string; @@ -43,16 +43,16 @@ export type Workspace = { secretDetectionIgnoreValues: string[]; }; -export type WorkspaceEnv = { +export type ProjectEnv = { id: string; name: string; slug: string; }; -export type WorkspaceTag = { id: string; name: string; slug: string }; +export type ProjectTag = { id: string; name: string; slug: string }; export type NameWorkspaceSecretsDTO = { - workspaceId: string; + projectId: string; secretsToUpdate: { secretName: string; secretId: string; @@ -76,30 +76,33 @@ export type CreateWorkspaceDTO = { }; export type UpdateProjectDTO = { - projectID: string; + projectId: string; newProjectName?: string; newProjectDescription?: string; newSlug?: string; secretSharing?: boolean; showSnapshotsLegacy?: boolean; secretDetectionIgnoreValues?: string[]; + pitVersionLimit?: number; + autoCapitalization?: boolean; + hasDeleteProtection?: boolean; }; export type UpdatePitVersionLimitDTO = { projectSlug: string; pitVersionLimit: number }; export type UpdateAuditLogsRetentionDTO = { projectSlug: string; auditLogsRetentionDays: number }; -export type ToggleAutoCapitalizationDTO = { workspaceID: string; state: boolean }; -export type ToggleDeleteProjectProtectionDTO = { workspaceID: string; state: boolean }; +export type ToggleAutoCapitalizationDTO = { projectID: string; state: boolean }; +export type ToggleDeleteProjectProtectionDTO = { projectID: string; state: boolean }; -export type DeleteWorkspaceDTO = { workspaceID: string }; +export type DeleteWorkspaceDTO = { projectID: string }; export type CreateEnvironmentDTO = { - workspaceId: string; + projectId: string; name: string; slug: string; }; export type ReorderEnvironmentsDTO = { - workspaceId: string; + projectId: string; environmentSlug: string; environmentName: string; otherEnvironmentSlug: string; @@ -107,18 +110,18 @@ export type ReorderEnvironmentsDTO = { }; export type UpdateEnvironmentDTO = { - workspaceId: string; + projectId: string; id: string; name?: string; slug?: string; position?: number; }; -export type DeleteEnvironmentDTO = { workspaceId: string; id: string }; +export type DeleteEnvironmentDTO = { projectId: string; id: string }; export type TUpdateWorkspaceUserRoleDTO = { membershipId: string; - workspaceId: string; + projectId: string; roles: ( | { role: string; @@ -136,7 +139,7 @@ export type TUpdateWorkspaceUserRoleDTO = { export type TUpdateWorkspaceIdentityRoleDTO = { identityId: string; - workspaceId: string; + projectId: string; roles: ( | { role: string; @@ -171,7 +174,7 @@ export type TUpdateWorkspaceGroupRoleDTO = { }; export type TListProjectIdentitiesDTO = { - workspaceId: string; + projectId: string; offset?: number; limit?: number; orderBy?: ProjectIdentityOrderBy; diff --git a/frontend/src/hooks/api/roles/mutation.tsx b/frontend/src/hooks/api/roles/mutation.tsx index 6df9aa937..e9caa68d5 100644 --- a/frontend/src/hooks/api/roles/mutation.tsx +++ b/frontend/src/hooks/api/roles/mutation.tsx @@ -22,7 +22,7 @@ export const useCreateProjectRole = () => { mutationFn: async ({ projectId, ...dto }: TCreateProjectRoleDTO) => { const { data: { role } - } = await apiRequest.post(`/api/v2/workspace/${projectId}/roles`, dto); + } = await apiRequest.post(`/api/v1/projects/${projectId}/roles`, dto); return role; }, onSuccess: (_, { projectId }) => { @@ -38,7 +38,7 @@ export const useUpdateProjectRole = () => { mutationFn: async ({ id, projectId, ...dto }: TUpdateProjectRoleDTO) => { const { data: { role } - } = await apiRequest.patch(`/api/v2/workspace/${projectId}/roles/${id}`, dto); + } = await apiRequest.patch(`/api/v1/projects/${projectId}/roles/${id}`, dto); return role; }, onSuccess: (_, { projectId, slug }) => { @@ -58,7 +58,7 @@ export const useDeleteProjectRole = () => { mutationFn: async ({ projectId, id }: TDeleteProjectRoleDTO) => { const { data: { role } - } = await apiRequest.delete(`/api/v2/workspace/${projectId}/roles/${id}`); + } = await apiRequest.delete(`/api/v1/projects/${projectId}/roles/${id}`); return role; }, onSuccess: (_, { projectId }) => { diff --git a/frontend/src/hooks/api/roles/queries.tsx b/frontend/src/hooks/api/roles/queries.tsx index a406b6d45..fd7b28db9 100644 --- a/frontend/src/hooks/api/roles/queries.tsx +++ b/frontend/src/hooks/api/roles/queries.tsx @@ -46,13 +46,13 @@ export const roleQueryKeys = { getOrgRole: (orgId: string, roleId: string) => [{ orgId, roleId }, "org-role"] as const, getUserOrgPermissions: ({ orgId }: TGetUserOrgPermissionsDTO) => ["user-permissions", { orgId }] as const, - getUserProjectPermissions: ({ workspaceId }: TGetUserProjectPermissionDTO) => - ["user-project-permissions", { workspaceId }] as const + getUserProjectPermissions: ({ projectId }: TGetUserProjectPermissionDTO) => + ["user-project-permissions", { projectId }] as const }; export const getProjectRoles = async (projectId: string) => { const { data } = await apiRequest.get<{ roles: Array> }>( - `/api/v2/workspace/${projectId}/roles` + `/api/v1/projects/${projectId}/roles` ); return data.roles; }; @@ -69,7 +69,7 @@ export const useGetProjectRoleBySlug = (projectId: string, roleSlug: string) => queryKey: roleQueryKeys.getProjectRoleBySlug(projectId, roleSlug), queryFn: async () => { const { data } = await apiRequest.get<{ role: TProjectRole }>( - `/api/v2/workspace/${projectId}/roles/slug/${roleSlug}` + `/api/v1/projects/${projectId}/roles/slug/${roleSlug}` ); return data.role; }, @@ -131,9 +131,7 @@ export const useGetUserOrgPermissions = ({ orgId }: TGetUserOrgPermissionsDTO) = } }); -export const fetchUserProjectPermissions = async ({ - workspaceId -}: TGetUserProjectPermissionDTO) => { +export const fetchUserProjectPermissions = async ({ projectId }: TGetUserProjectPermissionDTO) => { const { data } = await apiRequest.get<{ data: { permissions: PackRule>>[]; @@ -145,16 +143,16 @@ export const fetchUserProjectPermissions = async ({ actorName: string; }; }; - }>(`/api/v1/workspace/${workspaceId}/permissions`, {}); + }>(`/api/v1/projects/${projectId}/permissions`, {}); return data.data; }; -export const useGetUserProjectPermissions = ({ workspaceId }: TGetUserProjectPermissionDTO) => +export const useGetUserProjectPermissions = ({ projectId }: TGetUserProjectPermissionDTO) => useQuery({ - queryKey: roleQueryKeys.getUserProjectPermissions({ workspaceId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId }), - enabled: Boolean(workspaceId), + queryKey: roleQueryKeys.getUserProjectPermissions({ projectId }), + queryFn: () => fetchUserProjectPermissions({ projectId }), + enabled: Boolean(projectId), select: (data) => { const rule = unpackRules>>(data.permissions); const negatedRules = groupBy( diff --git a/frontend/src/hooks/api/roles/types.ts b/frontend/src/hooks/api/roles/types.ts index 12286bf9b..e94f13305 100644 --- a/frontend/src/hooks/api/roles/types.ts +++ b/frontend/src/hooks/api/roles/types.ts @@ -9,7 +9,7 @@ export enum ProjectMembershipRole { } export type TGetProjectRolesDTO = { - workspaceId?: string; + projectId?: string; }; export type TProjectRole = { @@ -52,7 +52,7 @@ export type TGetUserOrgPermissionsDTO = { }; export type TGetUserProjectPermissionDTO = { - workspaceId: string; + projectId: string; }; export type TCreateOrgRoleDTO = { diff --git a/frontend/src/hooks/api/secretApproval/mutation.tsx b/frontend/src/hooks/api/secretApproval/mutation.tsx index 8370d0367..c8fe51d19 100644 --- a/frontend/src/hooks/api/secretApproval/mutation.tsx +++ b/frontend/src/hooks/api/secretApproval/mutation.tsx @@ -11,7 +11,7 @@ export const useCreateSecretApprovalPolicy = () => { return useMutation({ mutationFn: async ({ environments, - workspaceId, + projectId, approvals, approvers, bypassers, @@ -20,9 +20,9 @@ export const useCreateSecretApprovalPolicy = () => { enforcementLevel, allowedSelfApprovals }) => { - const { data } = await apiRequest.post("/api/v1/secret-approvals", { + const { data } = await apiRequest.post("/api/v2/secret-approvals", { environments, - workspaceId, + projectId, approvals, approvers, bypassers, @@ -33,9 +33,9 @@ export const useCreateSecretApprovalPolicy = () => { }); return data; }, - onSuccess: (_, { workspaceId }) => { + onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: secretApprovalKeys.getApprovalPolicies(workspaceId) + queryKey: secretApprovalKeys.getApprovalPolicies(projectId) }); } }); @@ -56,7 +56,7 @@ export const useUpdateSecretApprovalPolicy = () => { allowedSelfApprovals, environments }) => { - const { data } = await apiRequest.patch(`/api/v1/secret-approvals/${id}`, { + const { data } = await apiRequest.patch(`/api/v2/secret-approvals/${id}`, { approvals, approvers, bypassers, @@ -68,9 +68,9 @@ export const useUpdateSecretApprovalPolicy = () => { }); return data; }, - onSuccess: (_, { workspaceId }) => { + onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: secretApprovalKeys.getApprovalPolicies(workspaceId) + queryKey: secretApprovalKeys.getApprovalPolicies(projectId) }); } }); @@ -81,12 +81,12 @@ export const useDeleteSecretApprovalPolicy = () => { return useMutation({ mutationFn: async ({ id }) => { - const { data } = await apiRequest.delete(`/api/v1/secret-approvals/${id}`); + const { data } = await apiRequest.delete(`/api/v2/secret-approvals/${id}`); return data; }, - onSuccess: (_, { workspaceId }) => { + onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: secretApprovalKeys.getApprovalPolicies(workspaceId) + queryKey: secretApprovalKeys.getApprovalPolicies(projectId) }); } }); diff --git a/frontend/src/hooks/api/secretApproval/queries.tsx b/frontend/src/hooks/api/secretApproval/queries.tsx index 52c3743fb..e81af93b8 100644 --- a/frontend/src/hooks/api/secretApproval/queries.tsx +++ b/frontend/src/hooks/api/secretApproval/queries.tsx @@ -10,54 +10,53 @@ import { } from "./types"; export const secretApprovalKeys = { - getApprovalPolicies: (workspaceId: string) => - [{ workspaceId }, "secret-approval-policies"] as const, - getApprovalPolicyOfABoard: (workspaceId: string, environment: string, secretPath: string) => [ - { workspaceId, environment, secretPath }, + getApprovalPolicies: (projectId: string) => [{ projectId }, "secret-approval-policies"] as const, + getApprovalPolicyOfABoard: (projectId: string, environment: string, secretPath: string) => [ + { projectId, environment, secretPath }, "Secret-approval-policy" ] }; -const fetchApprovalPolicies = async (workspaceId: string) => { +const fetchApprovalPolicies = async (projectId: string) => { const { data } = await apiRequest.get<{ approvals: TSecretApprovalPolicy[] }>( - "/api/v1/secret-approvals", - { params: { workspaceId } } + "/api/v2/secret-approvals", + { params: { projectId } } ); return data.approvals; }; export const useGetSecretApprovalPolicies = ({ - workspaceId, + projectId, options = {} }: TGetSecretApprovalPoliciesDTO & TReactQueryOptions) => useQuery({ - queryKey: secretApprovalKeys.getApprovalPolicies(workspaceId), - queryFn: () => fetchApprovalPolicies(workspaceId), + queryKey: secretApprovalKeys.getApprovalPolicies(projectId), + queryFn: () => fetchApprovalPolicies(projectId), ...options, - enabled: Boolean(workspaceId) && (options?.enabled ?? true) + enabled: Boolean(projectId) && (options?.enabled ?? true) }); const fetchApprovalPolicyOfABoard = async ( - workspaceId: string, + projectId: string, environment: string, secretPath: string ) => { const { data } = await apiRequest.get<{ policy: TSecretApprovalPolicy }>( - "/api/v1/secret-approvals/board", - { params: { workspaceId, environment, secretPath } } + "/api/v2/secret-approvals/board", + { params: { projectId, environment, secretPath } } ); return data.policy || ""; }; export const useGetSecretApprovalPolicyOfABoard = ({ - workspaceId, + projectId, secretPath = "/", environment, options = {} }: TGetSecretApprovalPolicyOfBoardDTO & TReactQueryOptions) => useQuery({ - queryKey: secretApprovalKeys.getApprovalPolicyOfABoard(workspaceId, environment, secretPath), - queryFn: () => fetchApprovalPolicyOfABoard(workspaceId, environment, secretPath), + queryKey: secretApprovalKeys.getApprovalPolicyOfABoard(projectId, environment, secretPath), + queryFn: () => fetchApprovalPolicyOfABoard(projectId, environment, secretPath), ...options, - enabled: Boolean(workspaceId && secretPath && environment) && (options?.enabled ?? true) + enabled: Boolean(projectId && secretPath && environment) && (options?.enabled ?? true) }); diff --git a/frontend/src/hooks/api/secretApproval/types.ts b/frontend/src/hooks/api/secretApproval/types.ts index 1785ffa8a..ac912c401 100644 --- a/frontend/src/hooks/api/secretApproval/types.ts +++ b/frontend/src/hooks/api/secretApproval/types.ts @@ -1,11 +1,11 @@ import { EnforcementLevel } from "../policies/enums"; -import { WorkspaceEnv } from "../workspace/types"; +import { ProjectEnv } from "../projects/types"; export type TSecretApprovalPolicy = { id: string; - workspace: string; + project: string; name: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; secretPath?: string; approvals: number; approvers: Approver[]; @@ -36,17 +36,17 @@ export type Bypasser = { }; export type TGetSecretApprovalPoliciesDTO = { - workspaceId: string; + projectId: string; }; export type TGetSecretApprovalPolicyOfBoardDTO = { - workspaceId: string; + projectId: string; environment: string; secretPath: string; }; export type TCreateSecretPolicyDTO = { - workspaceId: string; + projectId: string; name?: string; environments: string[]; secretPath: string; @@ -67,12 +67,12 @@ export type TUpdateSecretPolicyDTO = { allowedSelfApprovals?: boolean; enforcementLevel?: EnforcementLevel; // for invalidating list - workspaceId: string; + projectId: string; environments?: string[]; }; export type TDeleteSecretPolicyDTO = { id: string; // for invalidating list - workspaceId: string; + projectId: string; }; diff --git a/frontend/src/hooks/api/secretApprovalRequest/mutation.tsx b/frontend/src/hooks/api/secretApprovalRequest/mutation.tsx index 78e1b37a1..6a03b431c 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/mutation.tsx +++ b/frontend/src/hooks/api/secretApprovalRequest/mutation.tsx @@ -36,9 +36,9 @@ export const useUpdateSecretApprovalRequestStatus = () => { }); return data; }, - onSuccess: (_, { id, workspaceId }) => { + onSuccess: (_, { id, projectId }) => { queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.detail({ id }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); } }); }; @@ -53,10 +53,10 @@ export const usePerformSecretApprovalRequestMerge = () => { }); return data; }, - onSuccess: (_, { id, workspaceId }) => { + onSuccess: (_, { id, projectId }) => { queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.detail({ id }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.list({ workspaceId }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.list({ projectId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); } }); }; diff --git a/frontend/src/hooks/api/secretApprovalRequest/queries.tsx b/frontend/src/hooks/api/secretApprovalRequest/queries.tsx index a1736f70f..63cdd455e 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/queries.tsx +++ b/frontend/src/hooks/api/secretApprovalRequest/queries.tsx @@ -14,7 +14,7 @@ import { export const secretApprovalRequestKeys = { list: ({ - workspaceId, + projectId, environment, status, committer, @@ -23,20 +23,20 @@ export const secretApprovalRequestKeys = { search }: TGetSecretApprovalRequestList) => [ - { workspaceId, environment, status, committer, offset, limit, search }, + { projectId, environment, status, committer, offset, limit, search }, "secret-approval-requests" ] as const, detail: ({ id }: Omit) => [{ id }, "secret-approval-request-detail"] as const, - count: ({ workspaceId, policyId }: TGetSecretApprovalRequestCount) => [ - { workspaceId }, + count: ({ projectId, policyId }: TGetSecretApprovalRequestCount) => [ + { projectId }, "secret-approval-request-count", ...(policyId ? [policyId] : []) ] }; const fetchSecretApprovalRequestList = async ({ - workspaceId, + projectId, environment, committer, status = "open", @@ -49,7 +49,7 @@ const fetchSecretApprovalRequestList = async ({ totalCount: number; }>("/api/v1/secret-approval-requests", { params: { - workspaceId, + projectId, environment, committer, status, @@ -63,7 +63,7 @@ const fetchSecretApprovalRequestList = async ({ }; export const useGetSecretApprovalRequests = ({ - workspaceId, + projectId, environment, options = {}, status, @@ -74,7 +74,7 @@ export const useGetSecretApprovalRequests = ({ }: TGetSecretApprovalRequestList & TReactQueryOptions) => useQuery({ queryKey: secretApprovalRequestKeys.list({ - workspaceId, + projectId, environment, committer, status, @@ -84,7 +84,7 @@ export const useGetSecretApprovalRequests = ({ }), queryFn: () => fetchSecretApprovalRequestList({ - workspaceId, + projectId, environment, status, committer, @@ -92,7 +92,7 @@ export const useGetSecretApprovalRequests = ({ offset, search }), - enabled: Boolean(workspaceId) && (options?.enabled ?? true), + enabled: Boolean(projectId) && (options?.enabled ?? true), placeholderData: (previousData) => previousData }); @@ -127,19 +127,19 @@ export const useGetSecretApprovalRequestDetails = ({ }); const fetchSecretApprovalRequestCount = async ({ - workspaceId, + projectId, policyId }: TGetSecretApprovalRequestCount) => { const { data } = await apiRequest.get<{ approvals: TSecretApprovalRequestCount }>( "/api/v1/secret-approval-requests/count", - { params: { workspaceId, policyId } } + { params: { projectId, policyId } } ); return data.approvals; }; export const useGetSecretApprovalRequestCount = ({ - workspaceId, + projectId, policyId, options = {} }: TGetSecretApprovalRequestCount & { @@ -154,8 +154,8 @@ export const useGetSecretApprovalRequestCount = ({ >; }) => useQuery({ - queryKey: secretApprovalRequestKeys.count({ workspaceId, policyId }), + queryKey: secretApprovalRequestKeys.count({ projectId, policyId }), refetchInterval: 15000, - queryFn: () => fetchSecretApprovalRequestCount({ workspaceId, policyId }), - enabled: Boolean(workspaceId) && (options?.enabled ?? true) + queryFn: () => fetchSecretApprovalRequestCount({ projectId, policyId }), + enabled: Boolean(projectId) && (options?.enabled ?? true) }); diff --git a/frontend/src/hooks/api/secretApprovalRequest/types.ts b/frontend/src/hooks/api/secretApprovalRequest/types.ts index 0eef3fa3d..5a381e871 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/types.ts +++ b/frontend/src/hooks/api/secretApprovalRequest/types.ts @@ -55,7 +55,7 @@ export type TSecretApprovalRequest = { username: string; isOrgMembershipActive: boolean; }[]; - workspace: string; + project: string; environment: string; folderId: string; secretPath: string; @@ -110,7 +110,7 @@ export type TSecretApprovalRequestCount = { }; export type TGetSecretApprovalRequestList = { - workspaceId: string; + projectId: string; environment?: string; status?: "open" | "close"; committer?: string; @@ -120,7 +120,7 @@ export type TGetSecretApprovalRequestList = { }; export type TGetSecretApprovalRequestCount = { - workspaceId: string; + projectId: string; policyId?: string; }; @@ -137,11 +137,11 @@ export type TUpdateSecretApprovalReviewStatusDTO = { export type TUpdateSecretApprovalRequestStatusDTO = { status: "open" | "close"; id: string; - workspaceId: string; + projectId: string; }; export type TPerformSecretApprovalRequestMerge = { id: string; - workspaceId: string; + projectId: string; bypassReason?: string; }; diff --git a/frontend/src/hooks/api/secretFolders/queries.tsx b/frontend/src/hooks/api/secretFolders/queries.tsx index 9e12f329d..3e752eed3 100644 --- a/frontend/src/hooks/api/secretFolders/queries.tsx +++ b/frontend/src/hooks/api/secretFolders/queries.tsx @@ -30,10 +30,10 @@ export const folderQueryKeys = { ["secret-folders", "environment", projectId] as const }; -const fetchProjectFolders = async (workspaceId: string, environment: string, path = "/") => { - const { data } = await apiRequest.get<{ folders: TSecretFolder[] }>("/api/v1/folders", { +const fetchProjectFolders = async (projectId: string, environment: string, path = "/") => { + const { data } = await apiRequest.get<{ folders: TSecretFolder[] }>("/api/v2/folders", { params: { - workspaceId, + projectId, environment, path } @@ -57,7 +57,7 @@ export const useListProjectEnvironmentsFolders = ( queryKey: folderQueryKeys.getProjectEnvironmentsFolders(projectId), queryFn: async () => { const { data } = await apiRequest.get( - `/api/v1/workspace/${projectId}/environment-folder-tree` + `/api/v1/projects/${projectId}/environment-folder-tree` ); return data; }, @@ -145,9 +145,9 @@ export const useCreateFolder = () => { return useMutation({ mutationFn: async (dto) => { - const { data } = await apiRequest.post("/api/v1/folders", { + const { data } = await apiRequest.post("/api/v2/folders", { ...dto, - workspaceId: dto.projectId + projectId: dto.projectId }); return data; }, @@ -162,13 +162,13 @@ export const useCreateFolder = () => { queryKey: folderQueryKeys.getSecretFolders({ projectId, environment, path }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ workspaceId: projectId, environment, directory: path }) + queryKey: secretSnapshotKeys.list({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ workspaceId: projectId, environment, directory: path }) + queryKey: secretSnapshotKeys.count({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId: projectId, environment, directory: path }) + queryKey: commitKeys.count({ projectId, environment, directory: path }) }); } }); @@ -179,10 +179,10 @@ export const useUpdateFolder = () => { return useMutation({ mutationFn: async ({ path = "/", folderId, name, environment, projectId, description }) => { - const { data } = await apiRequest.patch(`/api/v1/folders/${folderId}`, { + const { data } = await apiRequest.patch(`/api/v2/folders/${folderId}`, { name, environment, - workspaceId: projectId, + projectId, path, description }); @@ -199,16 +199,16 @@ export const useUpdateFolder = () => { queryKey: folderQueryKeys.getSecretFolders({ projectId, environment, path }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ workspaceId: projectId, environment, directory: path }) + queryKey: secretSnapshotKeys.list({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ workspaceId: projectId, environment, directory: path }) + queryKey: secretSnapshotKeys.count({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId: projectId, environment, directory: path }) + queryKey: commitKeys.count({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId: projectId, environment, directory: path }) + queryKey: commitKeys.history({ projectId, environment, directory: path }) }); } }); @@ -219,10 +219,10 @@ export const useDeleteFolder = () => { return useMutation({ mutationFn: async ({ path = "/", folderId, environment, projectId }) => { - const { data } = await apiRequest.delete(`/api/v1/folders/${folderId}`, { + const { data } = await apiRequest.delete(`/api/v2/folders/${folderId}`, { data: { environment, - workspaceId: projectId, + projectId, path } }); @@ -239,16 +239,16 @@ export const useDeleteFolder = () => { queryKey: folderQueryKeys.getSecretFolders({ projectId, environment, path }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ workspaceId: projectId, environment, directory: path }) + queryKey: secretSnapshotKeys.list({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ workspaceId: projectId, environment, directory: path }) + queryKey: secretSnapshotKeys.count({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId: projectId, environment, directory: path }) + queryKey: commitKeys.count({ projectId, environment, directory: path }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId: projectId, environment, directory: path }) + queryKey: commitKeys.history({ projectId, environment, directory: path }) }); } }); @@ -258,9 +258,9 @@ export const useUpdateFolderBatch = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ projectSlug, folders }) => { - const { data } = await apiRequest.patch("/api/v1/folders/batch", { - projectSlug, + mutationFn: async ({ projectId, folders }) => { + const { data } = await apiRequest.patch("/api/v2/folders/batch", { + projectId, folders }); @@ -283,28 +283,28 @@ export const useUpdateFolderBatch = () => { }); queryClient.invalidateQueries({ queryKey: secretSnapshotKeys.list({ - workspaceId: projectId, + projectId, environment: folder.environment, directory: folder.path }) }); queryClient.invalidateQueries({ queryKey: secretSnapshotKeys.count({ - workspaceId: projectId, + projectId, environment: folder.environment, directory: folder.path }) }); queryClient.invalidateQueries({ queryKey: commitKeys.count({ - workspaceId: projectId, + projectId, environment: folder.environment, directory: folder.path }) }); queryClient.invalidateQueries({ queryKey: commitKeys.history({ - workspaceId: projectId, + projectId, environment: folder.environment, directory: folder.path }) diff --git a/frontend/src/hooks/api/secretFolders/types.ts b/frontend/src/hooks/api/secretFolders/types.ts index dc9bce70f..e9ee2ae5d 100644 --- a/frontend/src/hooks/api/secretFolders/types.ts +++ b/frontend/src/hooks/api/secretFolders/types.ts @@ -1,4 +1,4 @@ -import { WorkspaceEnv } from "@app/hooks/api/workspace/types"; +import { ProjectEnv } from "@app/hooks/api/projects/types"; export enum ReservedFolders { SecretReplication = "__reserve_replication_" @@ -22,7 +22,7 @@ export type TSecretFolder = { export type TSecretFolderWithPath = TSecretFolder & { path: string }; export type TProjectEnvironmentsFolders = { - [key: string]: WorkspaceEnv & { folders: TSecretFolderWithPath[] }; + [key: string]: ProjectEnv & { folders: TSecretFolderWithPath[] }; }; export type TGetProjectFoldersDTO = { @@ -63,7 +63,6 @@ export type TDeleteFolderDTO = { export type TUpdateFolderBatchDTO = { projectId: string; - projectSlug: string; folders: { name: string; environment: string; diff --git a/frontend/src/hooks/api/secretImports/mutation.tsx b/frontend/src/hooks/api/secretImports/mutation.tsx index 72254bae2..c9484ccfb 100644 --- a/frontend/src/hooks/api/secretImports/mutation.tsx +++ b/frontend/src/hooks/api/secretImports/mutation.tsx @@ -16,10 +16,10 @@ export const useCreateSecretImport = () => { return useMutation({ mutationFn: async ({ import: secretImport, environment, isReplication, projectId, path }) => { - const { data } = await apiRequest.post("/api/v1/secret-imports", { + const { data } = await apiRequest.post("/api/v2/secret-imports", { import: secretImport, environment, - workspaceId: projectId, + projectId, path, isReplication }); @@ -44,11 +44,11 @@ export const useUpdateSecretImport = () => { return useMutation({ mutationFn: async ({ environment, import: secretImports, projectId, path, id }) => { - const { data } = await apiRequest.patch(`/api/v1/secret-imports/${id}`, { + const { data } = await apiRequest.patch(`/api/v2/secret-imports/${id}`, { import: secretImports, environment, path, - workspaceId: projectId + projectId }); return data; }, @@ -69,10 +69,10 @@ export const useUpdateSecretImport = () => { export const useResyncSecretReplication = () => { return useMutation({ mutationFn: async ({ environment, projectId, path, id }) => { - const { data } = await apiRequest.post(`/api/v1/secret-imports/${id}/replication-resync`, { + const { data } = await apiRequest.post(`/api/v2/secret-imports/${id}/replication-resync`, { environment, path, - workspaceId: projectId + projectId }); return data; } @@ -84,9 +84,9 @@ export const useDeleteSecretImport = () => { return useMutation({ mutationFn: async ({ id, projectId, path, environment }) => { - const { data } = await apiRequest.delete(`/api/v1/secret-imports/${id}`, { + const { data } = await apiRequest.delete(`/api/v2/secret-imports/${id}`, { data: { - workspaceId: projectId, + projectId, path, environment } diff --git a/frontend/src/hooks/api/secretImports/queries.tsx b/frontend/src/hooks/api/secretImports/queries.tsx index ea6ea68ef..71716cb7c 100644 --- a/frontend/src/hooks/api/secretImports/queries.tsx +++ b/frontend/src/hooks/api/secretImports/queries.tsx @@ -30,10 +30,10 @@ export const secretImportKeys = { const fetchSecretImport = async ({ projectId, environment, path = "/" }: TGetSecretImports) => { const { data } = await apiRequest.get<{ secretImports: TSecretImport[] }>( - "/api/v1/secret-imports", + "/api/v2/secret-imports", { params: { - workspaceId: projectId, + projectId, environment, path } @@ -65,16 +65,12 @@ export const useGetSecretImports = ({ queryFn: () => fetchSecretImport({ path, projectId, environment }) }); -const fetchImportedSecrets = async ( - workspaceId: string, - environment: string, - directory?: string -) => { +const fetchImportedSecrets = async (projectId: string, environment: string, directory?: string) => { const { data } = await apiRequest.get<{ secrets: TImportedSecrets[] }>( - "/api/v1/secret-imports/secrets/raw", + "/api/v2/secret-imports/secrets", { params: { - workspaceId, + projectId, environment, path: directory } @@ -89,10 +85,10 @@ const fetchImportedFolders = async ({ path }: TGetImportedFoldersByEnvDTO) => { const { data } = await apiRequest.get<{ secretImports: TSecretImport[] }>( - "/api/v1/secret-imports", + "/api/v2/secret-imports", { params: { - workspaceId: projectId, + projectId, environment, path } diff --git a/frontend/src/hooks/api/secretImports/types.ts b/frontend/src/hooks/api/secretImports/types.ts index d950c2ca2..23690b33d 100644 --- a/frontend/src/hooks/api/secretImports/types.ts +++ b/frontend/src/hooks/api/secretImports/types.ts @@ -1,11 +1,11 @@ +import { ProjectEnv } from "../projects/types"; import { SecretV3Raw } from "../secrets/types"; -import { WorkspaceEnv } from "../workspace/types"; export type TSecretImport = { id: string; folderId: string; importPath: string; - importEnv: WorkspaceEnv; + importEnv: ProjectEnv; position: string; createdAt: string; updatedAt: string; @@ -25,7 +25,7 @@ export type TGetImportedFoldersByEnvDTO = { export type TImportedSecrets = { environment: string; - environmentInfo: WorkspaceEnv; + environmentInfo: ProjectEnv; secretPath: string; folderId: string; secrets: SecretV3Raw[]; diff --git a/frontend/src/hooks/api/secretRotation/types.ts b/frontend/src/hooks/api/secretRotation/types.ts index 19c4cdcdf..c5f939c5c 100644 --- a/frontend/src/hooks/api/secretRotation/types.ts +++ b/frontend/src/hooks/api/secretRotation/types.ts @@ -1,4 +1,4 @@ -import { WorkspaceEnv } from "../workspace/types"; +import { ProjectEnv } from "../projects/types"; export enum TProviderFunctionTypes { HTTP = "http", @@ -80,7 +80,7 @@ export type TSecretRotation = { customProvider: string; workspace: string; envId: string; - environment: WorkspaceEnv; + environment: ProjectEnv; secretPath: string; outputs: Array<{ key: string; diff --git a/frontend/src/hooks/api/secretSnapshots/queries.tsx b/frontend/src/hooks/api/secretSnapshots/queries.tsx index daee39054..f5492918c 100644 --- a/frontend/src/hooks/api/secretSnapshots/queries.tsx +++ b/frontend/src/hooks/api/secretSnapshots/queries.tsx @@ -14,25 +14,25 @@ import { } from "./types"; export const secretSnapshotKeys = { - list: ({ workspaceId, environment, directory }: Omit) => - [{ workspaceId, environment, directory }, "secret-snapshot"] as const, + list: ({ projectId, environment, directory }: Omit) => + [{ projectId, environment, directory }, "secret-snapshot"] as const, snapshotData: (snapshotId: string) => [{ snapshotId }, "secret-snapshot"] as const, - count: ({ environment, workspaceId, directory }: Omit) => [ - { workspaceId, environment, directory }, + count: ({ environment, projectId, directory }: Omit) => [ + { projectId, environment, directory }, "count", "secret-snapshot" ] }; const fetchWorkspaceSnaphots = async ({ - workspaceId, + projectId, environment, directory = "/", limit = 10, offset = 0 }: TGetSecretSnapshotsDTO & { offset: number }) => { const res = await apiRequest.get<{ secretSnapshots: TSecretSnapshot[] }>( - `/api/v1/workspace/${workspaceId}/secret-snapshots`, + `/api/v1/projects/${projectId}/secret-snapshots`, { params: { limit, @@ -49,7 +49,7 @@ const fetchWorkspaceSnaphots = async ({ export const useGetWorkspaceSnapshotList = (dto: TGetSecretSnapshotsDTO & { isPaused?: boolean }) => useInfiniteQuery({ initialPageParam: 0, - enabled: Boolean(dto.workspaceId && dto.environment) && !dto.isPaused, + enabled: Boolean(dto.projectId && dto.environment) && !dto.isPaused, queryKey: secretSnapshotKeys.list({ ...dto }), queryFn: ({ pageParam }) => fetchWorkspaceSnaphots({ ...dto, offset: pageParam }), getNextPageParam: (lastPage, pages) => @@ -115,12 +115,12 @@ export const useGetSnapshotSecrets = ({ snapshotId }: TSnapshotDataProps) => }); const fetchWorkspaceSecretSnaphotCount = async ( - workspaceId: string, + projectId: string, environment: string, directory = "/" ) => { const res = await apiRequest.get<{ count: number }>( - `/api/v1/workspace/${workspaceId}/secret-snapshots/count`, + `/api/v1/projects/${projectId}/secret-snapshots/count`, { params: { environment, @@ -132,15 +132,15 @@ const fetchWorkspaceSecretSnaphotCount = async ( }; export const useGetWsSnapshotCount = ({ - workspaceId, + projectId, environment, directory, isPaused }: Omit & { isPaused?: boolean }) => useQuery({ - enabled: Boolean(workspaceId && environment) && !isPaused, - queryKey: secretSnapshotKeys.count({ workspaceId, environment, directory }), - queryFn: () => fetchWorkspaceSecretSnaphotCount(workspaceId, environment, directory) + enabled: Boolean(projectId && environment) && !isPaused, + queryKey: secretSnapshotKeys.count({ projectId, environment, directory }), + queryFn: () => fetchWorkspaceSecretSnaphotCount(projectId, environment, directory) }); export const usePerformSecretRollback = () => { @@ -151,22 +151,22 @@ export const usePerformSecretRollback = () => { const { data } = await apiRequest.post(`/api/v1/secret-snapshot/${snapshotId}/rollback`); return data; }, - onSuccess: (_, { workspaceId, environment, directory }) => { + onSuccess: (_, { projectId, environment, directory }) => { queryClient.invalidateQueries({ - queryKey: [{ workspaceId, environment, secretPath: directory }, "secrets"] + queryKey: [{ projectId, environment, secretPath: directory }, "secrets"] }); queryClient.invalidateQueries({ - queryKey: ["secret-folders", { projectId: workspaceId, environment, path: directory }] + queryKey: ["secret-folders", { projectId, environment, path: directory }] }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ workspaceId, environment, directory }) + queryKey: secretSnapshotKeys.list({ projectId, environment, directory }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ workspaceId, environment, directory }) + queryKey: secretSnapshotKeys.count({ projectId, environment, directory }) }); queryClient.invalidateQueries({ queryKey: dashboardKeys.getDashboardSecrets({ - projectId: workspaceId, + projectId, secretPath: directory ?? "/" }) }); diff --git a/frontend/src/hooks/api/secretSnapshots/types.ts b/frontend/src/hooks/api/secretSnapshots/types.ts index e7ebb18de..9b1f95480 100644 --- a/frontend/src/hooks/api/secretSnapshots/types.ts +++ b/frontend/src/hooks/api/secretSnapshots/types.ts @@ -1,9 +1,9 @@ import { SecretVersions } from "../secrets/types"; -import { WorkspaceEnv } from "../types"; +import { ProjectEnv } from "../types"; export type TSecretSnapshot = { id: string; - workspace: string; + projectId: string; secretVersions: string[]; createdAt: string; updatedAt: string; @@ -13,7 +13,7 @@ export type TSnapshotData = Omit & { id: string; secretVersions: (SecretVersions & { isRotatedSecret?: boolean })[]; folderVersion: Array<{ name: string; id: string }>; - environment: WorkspaceEnv; + environment: ProjectEnv; }; export type TSnapshotDataProps = { @@ -22,7 +22,7 @@ export type TSnapshotDataProps = { }; export type TGetSecretSnapshotsDTO = { - workspaceId: string; + projectId: string; limit: number; environment: string; directory?: string; @@ -30,7 +30,7 @@ export type TGetSecretSnapshotsDTO = { export type TSecretRollbackDTO = { snapshotId: string; - workspaceId: string; + projectId: string; environment: string; directory?: string; }; diff --git a/frontend/src/hooks/api/secrets/mutations.tsx b/frontend/src/hooks/api/secrets/mutations.tsx index 11ebad4b1..de960cd04 100644 --- a/frontend/src/hooks/api/secrets/mutations.tsx +++ b/frontend/src/hooks/api/secrets/mutations.tsx @@ -33,18 +33,18 @@ export const useCreateSecretV3 = ({ secretPath = "/", type, environment, - workspaceId, + projectId, secretKey, secretValue, secretComment, skipMultilineEncoding, tagIds }) => { - const { data } = await apiRequest.post(`/api/v3/secrets/raw/${secretKey}`, { + const { data } = await apiRequest.post(`/api/v4/secrets/${secretKey}`, { secretPath, type, environment, - workspaceId, + projectId, secretValue, secretComment, skipMultilineEncoding, @@ -52,26 +52,26 @@ export const useCreateSecretV3 = ({ }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options }); @@ -88,7 +88,7 @@ export const useUpdateSecretV3 = ({ secretPath = "/", type, environment, - workspaceId, + projectId, secretKey, secretValue, tagIds, @@ -100,8 +100,8 @@ export const useUpdateSecretV3 = ({ skipMultilineEncoding, secretMetadata }) => { - const { data } = await apiRequest.patch(`/api/v3/secrets/raw/${secretKey}`, { - workspaceId, + const { data } = await apiRequest.patch(`/api/v4/secrets/${secretKey}`, { + projectId, environment, type, secretReminderNote, @@ -117,26 +117,26 @@ export const useUpdateSecretV3 = ({ }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options }); @@ -150,17 +150,10 @@ export const useDeleteSecretV3 = ({ const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ - secretPath = "/", - type, - environment, - workspaceId, - secretKey, - secretId - }) => { - const { data } = await apiRequest.delete(`/api/v3/secrets/raw/${secretKey}`, { + mutationFn: async ({ secretPath = "/", type, environment, projectId, secretKey, secretId }) => { + const { data } = await apiRequest.delete(`/api/v4/secrets/${secretKey}`, { data: { - workspaceId, + projectId, environment, type, secretPath, @@ -169,26 +162,26 @@ export const useDeleteSecretV3 = ({ }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options }); @@ -202,35 +195,35 @@ export const useCreateSecretBatch = ({ const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ secretPath = "/", workspaceId, environment, secrets }) => { - const { data } = await apiRequest.post("/api/v3/secrets/batch/raw", { - workspaceId, + mutationFn: async ({ secretPath = "/", projectId, environment, secrets }) => { + const { data } = await apiRequest.post("/api/v4/secrets/batch", { + projectId, environment, secretPath, secrets }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options }); @@ -244,35 +237,35 @@ export const useUpdateSecretBatch = ({ const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ secretPath = "/", workspaceId, environment, secrets }) => { - const { data } = await apiRequest.patch("/api/v3/secrets/batch/raw", { - workspaceId, + mutationFn: async ({ secretPath = "/", projectId, environment, secrets }) => { + const { data } = await apiRequest.patch("/api/v4/secrets/batch", { + projectId, environment, secretPath, secrets }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options }); @@ -286,10 +279,10 @@ export const useDeleteSecretBatch = ({ const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ secretPath = "/", workspaceId, environment, secrets }) => { - const { data } = await apiRequest.delete("/api/v3/secrets/batch/raw", { + mutationFn: async ({ secretPath = "/", projectId, environment, secrets }) => { + const { data } = await apiRequest.delete("/api/v4/secrets/batch", { data: { - workspaceId, + projectId, environment, secretPath, secrets @@ -297,26 +290,26 @@ export const useDeleteSecretBatch = ({ }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options }); @@ -340,23 +333,23 @@ export const useMoveSecrets = ({ mutationFn: async ({ sourceEnvironment, sourceSecretPath, - projectSlug, destinationEnvironment, destinationSecretPath, secretIds, - shouldOverwrite + shouldOverwrite, + projectId }) => { const { data } = await apiRequest.post<{ isSourceUpdated: boolean; isDestinationUpdated: boolean; - }>("/api/v3/secrets/move", { + }>("/api/v4/secrets/move", { sourceEnvironment, sourceSecretPath, - projectSlug, destinationEnvironment, destinationSecretPath, secretIds, - shouldOverwrite + shouldOverwrite, + projectId }); return data; @@ -370,7 +363,7 @@ export const useMoveSecrets = ({ }); queryClient.invalidateQueries({ queryKey: secretKeys.getProjectSecret({ - workspaceId: projectId, + projectId, environment: sourceEnvironment, secretPath: sourceSecretPath }) @@ -378,33 +371,33 @@ export const useMoveSecrets = ({ queryClient.invalidateQueries({ queryKey: secretSnapshotKeys.list({ environment: sourceEnvironment, - workspaceId: projectId, + projectId, directory: sourceSecretPath }) }); queryClient.invalidateQueries({ queryKey: secretSnapshotKeys.count({ environment: sourceEnvironment, - workspaceId: projectId, + projectId, directory: sourceSecretPath }) }); queryClient.invalidateQueries({ queryKey: commitKeys.count({ - workspaceId: projectId, + projectId, environment: sourceEnvironment, directory: sourceSecretPath }) }); queryClient.invalidateQueries({ queryKey: commitKeys.history({ - workspaceId: projectId, + projectId, environment: sourceEnvironment, directory: sourceSecretPath }) }); queryClient.invalidateQueries({ - queryKey: secretApprovalRequestKeys.count({ workspaceId: projectId }) + queryKey: secretApprovalRequestKeys.count({ projectId }) }); }, ...options @@ -412,14 +405,14 @@ export const useMoveSecrets = ({ }; export const createSecret = async (dto: TCreateSecretsV3DTO) => { - const { data } = await apiRequest.post(`/api/v3/secrets/${dto.secretKey}`, dto); + const { data } = await apiRequest.post(`/api/v4/secrets/${dto.secretKey}`, dto); return data; }; export const useBackfillSecretReference = () => useMutation<{ message: string }, object, { projectId: string }>({ mutationFn: async ({ projectId }) => { - const { data } = await apiRequest.post("/api/v3/secrets/backfill-secret-references", { + const { data } = await apiRequest.post("/api/v4/secrets/backfill-secret-references", { projectId }); return data.message; @@ -432,16 +425,16 @@ export const useCreateCommit = () => { object, object, { - workspaceId: string; + projectId: string; environment: string; secretPath: string; pendingChanges: PendingChanges; message: string; } >({ - mutationFn: async ({ workspaceId, environment, secretPath, pendingChanges, message }) => { + mutationFn: async ({ projectId, environment, secretPath, pendingChanges, message }) => { const { data } = await apiRequest.post("/api/v1/pit/batch/commit", { - projectId: workspaceId, + projectId, environment, secretPath, changes: { @@ -501,26 +494,26 @@ export const useCreateCommit = () => { }); return data; }, - onSuccess: (_, { workspaceId, environment, secretPath }) => { + onSuccess: (_, { projectId, environment, secretPath }) => { queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) + queryKey: dashboardKeys.getDashboardSecrets({ projectId, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.list({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.list({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: secretSnapshotKeys.count({ environment, workspaceId, directory: secretPath }) + queryKey: secretSnapshotKeys.count({ environment, projectId, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.count({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.count({ projectId, environment, directory: secretPath }) }); queryClient.invalidateQueries({ - queryKey: commitKeys.history({ workspaceId, environment, directory: secretPath }) + queryKey: commitKeys.history({ projectId, environment, directory: secretPath }) }); - queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ workspaceId }) }); + queryClient.invalidateQueries({ queryKey: secretApprovalRequestKeys.count({ projectId }) }); } }); }; diff --git a/frontend/src/hooks/api/secrets/queries.tsx b/frontend/src/hooks/api/secrets/queries.tsx index 443b74df8..df3a78c35 100644 --- a/frontend/src/hooks/api/secrets/queries.tsx +++ b/frontend/src/hooks/api/secrets/queries.tsx @@ -27,35 +27,35 @@ import { export const secretKeys = { // this is also used in secretSnapshot part getProjectSecret: ({ - workspaceId, + projectId, environment, secretPath, viewSecretValue }: TGetProjectSecretsKey) => - [{ workspaceId, environment, secretPath, viewSecretValue }, "secrets"] as const, + [{ projectId, environment, secretPath, viewSecretValue }, "secrets"] as const, getSecretVersion: (secretId: string) => [{ secretId }, "secret-versions"] as const, getSecretAccessList: ({ - workspaceId, + projectId, environment, secretPath, secretKey }: TGetSecretAccessListDTO) => - ["secret-access-list", { workspaceId, environment, secretPath, secretKey }] as const, + ["secret-access-list", { projectId, environment, secretPath, secretKey }] as const, getSecretReferenceTree: (dto: TGetSecretReferenceTreeDTO) => ["secret-reference-tree", dto] }; export const fetchProjectSecrets = async ({ - workspaceId, + projectId, environment, secretPath, includeImports, expandSecretReferences, viewSecretValue }: TGetProjectSecretsKey) => { - const { data } = await apiRequest.get("/api/v3/secrets/raw", { + const { data } = await apiRequest.get("/api/v4/secrets", { params: { environment, - workspaceId, + projectId, secretPath, viewSecretValue, expandSecretReferences, @@ -116,7 +116,7 @@ export const mergePersonalSecrets = (rawSecrets: SecretV3Raw[]) => { }; export const useGetProjectSecrets = ({ - workspaceId, + projectId, environment, secretPath, viewSecretValue, @@ -135,14 +135,14 @@ export const useGetProjectSecrets = ({ useQuery({ ...options, // wait for all values to be available - enabled: Boolean(workspaceId && environment) && (options?.enabled ?? true), + enabled: Boolean(projectId && environment) && (options?.enabled ?? true), queryKey: secretKeys.getProjectSecret({ - workspaceId, + projectId, environment, secretPath, viewSecretValue }), - queryFn: () => fetchProjectSecrets({ workspaceId, environment, secretPath, viewSecretValue }), + queryFn: () => fetchProjectSecrets({ projectId, environment, secretPath, viewSecretValue }), select: useCallback( (data: Awaited>) => mergePersonalSecrets(data.secrets), [] @@ -150,7 +150,7 @@ export const useGetProjectSecrets = ({ }); export const useGetProjectSecretsAllEnv = ({ - workspaceId, + projectId, envs, secretPath }: TGetProjectSecretsAllEnvDTO) => { @@ -159,11 +159,11 @@ export const useGetProjectSecretsAllEnv = ({ const secrets = useQueries({ queries: envs.map((environment) => ({ queryKey: secretKeys.getProjectSecret({ - workspaceId, + projectId, environment, secretPath }), - enabled: Boolean(workspaceId && environment), + enabled: Boolean(projectId && environment), onError: (error: unknown) => { if (axios.isAxiosError(error) && !isErrorHandled) { const { message, requestId } = error.response?.data as { @@ -187,7 +187,7 @@ export const useGetProjectSecretsAllEnv = ({ setIsErrorHandled.on(); } }, - queryFn: () => fetchProjectSecrets({ workspaceId, environment, secretPath }), + queryFn: () => fetchProjectSecrets({ projectId, environment, secretPath }), staleTime: 60 * 1000, // eslint-disable-next-line react-hooks/rules-of-hooks select: useCallback( @@ -270,7 +270,7 @@ export const useGetSecretAccessList = (dto: TGetSecretAccessListDTO) => users: SecretAccessListEntry[]; }>(`/api/v1/secrets/${dto.secretKey}/access-list`, { params: { - workspaceId: dto.workspaceId, + projectId: dto.projectId, environment: dto.environment, secretPath: dto.secretPath } @@ -287,11 +287,11 @@ const fetchSecretReferenceTree = async ({ environmentSlug }: TGetSecretReferenceTreeDTO) => { const { data } = await apiRequest.get<{ tree: TSecretReferenceTraceNode; value: string }>( - `/api/v3/secrets/raw/${secretKey}/secret-reference-tree`, + `/api/v4/secrets/${secretKey}/secret-reference-tree`, { params: { secretPath, - workspaceId: projectId, + projectId, environment: environmentSlug } } diff --git a/frontend/src/hooks/api/secrets/types.ts b/frontend/src/hooks/api/secrets/types.ts index 1b232cfac..327d3659d 100644 --- a/frontend/src/hooks/api/secrets/types.ts +++ b/frontend/src/hooks/api/secrets/types.ts @@ -17,30 +17,6 @@ export type SecretReminderRecipient = { }; id: string; }; -export type EncryptedSecret = { - id: string; - version: number; - workspace: string; - type: SecretType; - environment: string; - secretKeyCiphertext: string; - secretKeyIV: string; - secretKeyTag: string; - secretValueCiphertext: string; - secretValueIV: string; - secretValueTag: string; - secretValueHidden: boolean; - __v: number; - createdAt: string; - updatedAt: string; - skipMultilineEncoding?: boolean; - secretCommentCiphertext: string; - secretCommentIV: string; - secretCommentTag: string; - secretReminderRepeatDays?: number | null; - secretReminderNote?: string | null; - tags: WsTag[]; -}; // both personal and shared secret stitched together for dashboard export type SecretV3RawSanitized = { @@ -76,7 +52,7 @@ export type SecretV3RawSanitized = { export type SecretV3Raw = { id: string; _id: string; - workspace: string; + project: string; environment: string; version: number; type: string; @@ -113,7 +89,7 @@ export type SecretVersions = { id: string; secretId: string; version: number; - workspace: string; + project: string; type: SecretType; isDeleted: boolean; envId: string; @@ -136,7 +112,7 @@ export type SecretVersions = { // dto export type TGetProjectSecretsKey = { - workspaceId: string; + projectId: string; environment: string; secretPath?: string; includeImports?: boolean; @@ -148,7 +124,7 @@ export type TGetProjectSecretsKey = { export type TGetProjectSecretsDTO = TGetProjectSecretsKey; export type TGetProjectSecretsAllEnvDTO = { - workspaceId: string; + projectId: string; envs: string[]; folderId?: string; secretPath?: string; @@ -162,7 +138,7 @@ export type GetSecretVersionsDTO = { }; export type TGetSecretAccessListDTO = { - workspaceId: string; + projectId: string; environment: string; secretPath: string; secretKey: string; @@ -174,14 +150,14 @@ export type TCreateSecretsV3DTO = { secretComment: string; skipMultilineEncoding?: boolean; secretPath: string; - workspaceId: string; + projectId: string; environment: string; type: SecretType; tagIds?: string[]; }; export type TUpdateSecretsV3DTO = { - workspaceId: string; + projectId: string; environment: string; secretPath: string; type: SecretType; @@ -198,7 +174,7 @@ export type TUpdateSecretsV3DTO = { }; export type TDeleteSecretsV3DTO = { - workspaceId: string; + projectId: string; environment: string; type: SecretType; secretPath: string; @@ -207,7 +183,7 @@ export type TDeleteSecretsV3DTO = { }; export type TCreateSecretBatchDTO = { - workspaceId: string; + projectId: string; environment: string; secretPath: string; secrets: Array<{ @@ -224,7 +200,7 @@ export type TCreateSecretBatchDTO = { }; export type TUpdateSecretBatchDTO = { - workspaceId: string; + projectId: string; environment: string; secretPath: string; secrets: Array<{ @@ -241,7 +217,7 @@ export type TUpdateSecretBatchDTO = { }; export type TDeleteSecretBatchDTO = { - workspaceId: string; + projectId: string; environment: string; secretPath: string; secrets: Array<{ @@ -251,7 +227,6 @@ export type TDeleteSecretBatchDTO = { }; export type TMoveSecretsDTO = { - projectSlug: string; projectId: string; sourceEnvironment: string; sourceSecretPath: string; diff --git a/frontend/src/hooks/api/serviceTokens/queries.tsx b/frontend/src/hooks/api/serviceTokens/queries.tsx index 06b9b09c6..41421b279 100644 --- a/frontend/src/hooks/api/serviceTokens/queries.tsx +++ b/frontend/src/hooks/api/serviceTokens/queries.tsx @@ -13,9 +13,9 @@ const serviceTokenKeys = { getAllWorkspaceServiceToken: (workspaceID: string) => [{ workspaceID }, "service-tokens"] as const }; -const fetchWorkspaceServiceTokens = async (workspaceID: string) => { +const fetchWorkspaceServiceTokens = async (projectID: string) => { const { data } = await apiRequest.get<{ serviceTokenData: ServiceToken[] }>( - `/api/v1/workspace/${workspaceID}/service-token-data` + `/api/v1/projects/${projectID}/service-token-data` ); return data.serviceTokenData; diff --git a/frontend/src/hooks/api/sshCa/mutations.tsx b/frontend/src/hooks/api/sshCa/mutations.tsx index c7e90c3b9..fc6c43ef4 100644 --- a/frontend/src/hooks/api/sshCa/mutations.tsx +++ b/frontend/src/hooks/api/sshCa/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace/query-keys"; +import { projectKeys } from "../projects/query-keys"; import { TCreateSshCaDTO, TDeleteSshCaDTO, @@ -28,7 +28,7 @@ export const useCreateSshCa = () => { return ca; }, onSuccess: ({ projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceSshCas(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectSshCas(projectId) }); } }); }; @@ -43,7 +43,7 @@ export const useUpdateSshCa = () => { return ca; }, onSuccess: ({ projectId }, { caId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceSshCas(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectSshCas(projectId) }); queryClient.invalidateQueries({ queryKey: sshCaKeys.getSshCaById(caId) }); } }); @@ -59,7 +59,7 @@ export const useDeleteSshCa = () => { return ca; }, onSuccess: ({ projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceSshCas(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectSshCas(projectId) }); } }); }; @@ -76,7 +76,7 @@ export const useSignSshKey = () => { }, onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.allWorkspaceSshCertificates(projectId) + queryKey: projectKeys.allProjectSshCertificates(projectId) }); } }); @@ -94,7 +94,7 @@ export const useIssueSshCreds = () => { }, onSuccess: (_, { projectId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.allWorkspaceSshCertificates(projectId) + queryKey: projectKeys.allProjectSshCertificates(projectId) }); } }); diff --git a/frontend/src/hooks/api/sshHost/mutations.tsx b/frontend/src/hooks/api/sshHost/mutations.tsx index f6b831f3e..0c1b67103 100644 --- a/frontend/src/hooks/api/sshHost/mutations.tsx +++ b/frontend/src/hooks/api/sshHost/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace/query-keys"; +import { projectKeys } from "../projects/query-keys"; import { TCreateSshHostDTO, TDeleteSshHostDTO, TSshHost, TUpdateSshHostDTO } from "./types"; export const useCreateSshHost = () => { @@ -13,7 +13,7 @@ export const useCreateSshHost = () => { return host; }, onSuccess: ({ projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceSshHosts(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectSshHosts(projectId) }); } }); }; @@ -26,7 +26,7 @@ export const useUpdateSshHost = () => { return host; }, onSuccess: ({ projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceSshHosts(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectSshHosts(projectId) }); } }); }; @@ -39,7 +39,7 @@ export const useDeleteSshHost = () => { return host; }, onSuccess: ({ projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceSshHosts(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectSshHosts(projectId) }); } }); }; diff --git a/frontend/src/hooks/api/sshHostGroup/mutations.tsx b/frontend/src/hooks/api/sshHostGroup/mutations.tsx index b75cff187..fa9eebb07 100644 --- a/frontend/src/hooks/api/sshHostGroup/mutations.tsx +++ b/frontend/src/hooks/api/sshHostGroup/mutations.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace/query-keys"; +import { projectKeys } from "../projects/query-keys"; import { sshHostGroupKeys } from "./queries"; import { TCreateSshHostGroupDTO, @@ -20,7 +20,7 @@ export const useCreateSshHostGroup = () => { }, onSuccess: ({ projectId, id }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId) + queryKey: projectKeys.getProjectSshHostGroups(projectId) }); queryClient.invalidateQueries({ queryKey: sshHostGroupKeys.getSshHostGroupById(id) @@ -41,10 +41,10 @@ export const useUpdateSshHostGroup = () => { }, onSuccess: ({ projectId }, { sshHostGroupId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId) + queryKey: projectKeys.getProjectSshHostGroups(projectId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceSshHosts(projectId) + queryKey: projectKeys.getProjectSshHosts(projectId) }); queryClient.invalidateQueries({ queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId) @@ -64,10 +64,10 @@ export const useDeleteSshHostGroup = () => { }, onSuccess: ({ projectId }, { sshHostGroupId }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId) + queryKey: projectKeys.getProjectSshHostGroups(projectId) }); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceSshHosts(projectId) + queryKey: projectKeys.getProjectSshHosts(projectId) }); queryClient.invalidateQueries({ queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId) diff --git a/frontend/src/hooks/api/tags/queries.tsx b/frontend/src/hooks/api/tags/queries.tsx index bdbb9659d..0234cec4d 100644 --- a/frontend/src/hooks/api/tags/queries.tsx +++ b/frontend/src/hooks/api/tags/queries.tsx @@ -4,23 +4,21 @@ import { apiRequest } from "@app/config/request"; import { CreateTagDTO, DeleteTagDTO, UserWsTags, WsTag } from "./types"; -const workspaceTags = { - getWsTags: (workspaceID: string) => ["workspace-tags", { workspaceID }] as const +const projectTags = { + getWsTags: (projectID: string) => ["project-tags", { projectID }] as const }; -const fetchWsTag = async (workspaceID: string) => { - const { data } = await apiRequest.get<{ workspaceTags: UserWsTags }>( - `/api/v1/workspace/${workspaceID}/tags` - ); +const fetchWsTag = async (projectID: string) => { + const { data } = await apiRequest.get<{ tags: UserWsTags }>(`/api/v1/projects/${projectID}/tags`); - return data.workspaceTags; + return data.tags; }; -export const useGetWsTags = (workspaceID: string) => { +export const useGetWsTags = (projectID: string) => { return useQuery({ - queryKey: workspaceTags.getWsTags(workspaceID), - queryFn: () => fetchWsTag(workspaceID), - enabled: Boolean(workspaceID) + queryKey: projectTags.getWsTags(projectID), + queryFn: () => fetchWsTag(projectID), + enabled: Boolean(projectID) }); }; @@ -28,18 +26,15 @@ export const useCreateWsTag = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ workspaceID, tagColor, tagSlug }) => { - const { data } = await apiRequest.post<{ workspaceTag: WsTag }>( - `/api/v1/workspace/${workspaceID}/tags`, - { - color: tagColor || "", - slug: tagSlug - } - ); - return data.workspaceTag; + mutationFn: async ({ projectId: projectID, tagColor, tagSlug }) => { + const { data } = await apiRequest.post<{ tag: WsTag }>(`/api/v1/projects/${projectID}/tags`, { + color: tagColor || "", + slug: tagSlug + }); + return data.tag; }, onSuccess: (tagData) => { - queryClient.invalidateQueries({ queryKey: workspaceTags.getWsTags(tagData?.projectId) }); + queryClient.invalidateQueries({ queryKey: projectTags.getWsTags(tagData?.projectId) }); } }); }; @@ -49,13 +44,13 @@ export const useDeleteWsTag = () => { return useMutation({ mutationFn: async ({ tagID, projectId }) => { - const { data } = await apiRequest.delete<{ workspaceTag: WsTag }>( - `/api/v1/workspace/${projectId}/tags/${tagID}` + const { data } = await apiRequest.delete<{ tag: WsTag }>( + `/api/v1/projects/${projectId}/tags/${tagID}` ); - return data.workspaceTag; + return data.tag; }, onSuccess: (tagData) => { - queryClient.invalidateQueries({ queryKey: workspaceTags.getWsTags(tagData?.projectId) }); + queryClient.invalidateQueries({ queryKey: projectTags.getWsTags(tagData?.projectId) }); } }); }; diff --git a/frontend/src/hooks/api/tags/types.ts b/frontend/src/hooks/api/tags/types.ts index 72d710cfa..09ac22147 100644 --- a/frontend/src/hooks/api/tags/types.ts +++ b/frontend/src/hooks/api/tags/types.ts @@ -13,7 +13,7 @@ export type WsTag = { export type WorkspaceTag = { id: string; name: string; slug: string }; export type CreateTagDTO = { - workspaceID: string; + projectId: string; tagSlug: string; tagColor: string; }; diff --git a/frontend/src/hooks/api/trustedIps/queries.ts b/frontend/src/hooks/api/trustedIps/queries.ts index 57a5d5844..36815b313 100644 --- a/frontend/src/hooks/api/trustedIps/queries.ts +++ b/frontend/src/hooks/api/trustedIps/queries.ts @@ -5,15 +5,15 @@ import { apiRequest } from "@app/config/request"; import { TrustedIp } from "./types"; const trustedIps = { - getTrustedIps: (workspaceId: string) => [{ workspaceId }, "trusted-ips"] as const + getTrustedIps: (projectId: string) => [{ projectId }, "trusted-ips"] as const }; -export const useGetTrustedIps = (workspaceId: string) => { +export const useGetTrustedIps = (projectId: string) => { return useQuery({ - queryKey: trustedIps.getTrustedIps(workspaceId), + queryKey: trustedIps.getTrustedIps(projectId), queryFn: async () => { const { data } = await apiRequest.get<{ trustedIps: TrustedIp[] }>( - `/api/v1/workspace/${workspaceId}/trusted-ips` + `/api/v1/projects/${projectId}/trusted-ips` ); return data.trustedIps; @@ -25,17 +25,17 @@ export const useAddTrustedIp = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ - workspaceId, + projectId, ipAddress, comment, isActive }: { - workspaceId: string; + projectId: string; ipAddress: string; comment?: string; isActive: boolean; }) => { - const { data } = await apiRequest.post(`/api/v1/workspace/${workspaceId}/trusted-ips`, { + const { data } = await apiRequest.post(`/api/v1/projects/${projectId}/trusted-ips`, { ipAddress, ...(comment ? { comment } : {}), isActive @@ -44,7 +44,7 @@ export const useAddTrustedIp = () => { return data; }, onSuccess(_, dto) { - queryClient.invalidateQueries({ queryKey: trustedIps.getTrustedIps(dto.workspaceId) }); + queryClient.invalidateQueries({ queryKey: trustedIps.getTrustedIps(dto.projectId) }); } }); }; @@ -53,20 +53,20 @@ export const useUpdateTrustedIp = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ - workspaceId, + projectId, trustedIpId, ipAddress, comment, isActive }: { - workspaceId: string; + projectId: string; trustedIpId: string; ipAddress: string; comment?: string; isActive: boolean; }) => { const { data } = await apiRequest.patch( - `/api/v1/workspace/${workspaceId}/trusted-ips/${trustedIpId}`, + `/api/v1/projects/${projectId}/trusted-ips/${trustedIpId}`, { ipAddress, ...(comment ? { comment } : {}), @@ -77,7 +77,7 @@ export const useUpdateTrustedIp = () => { return data; }, onSuccess(_, dto) { - queryClient.invalidateQueries({ queryKey: trustedIps.getTrustedIps(dto.workspaceId) }); + queryClient.invalidateQueries({ queryKey: trustedIps.getTrustedIps(dto.projectId) }); } }); }; @@ -85,21 +85,15 @@ export const useUpdateTrustedIp = () => { export const useDeleteTrustedIp = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ - workspaceId, - trustedIpId - }: { - workspaceId: string; - trustedIpId: string; - }) => { + mutationFn: async ({ projectId, trustedIpId }: { projectId: string; trustedIpId: string }) => { const { data } = await apiRequest.delete( - `/api/v1/workspace/${workspaceId}/trusted-ips/${trustedIpId}` + `/api/v1/projects/${projectId}/trusted-ips/${trustedIpId}` ); return data; }, onSuccess(_, dto) { - queryClient.invalidateQueries({ queryKey: trustedIps.getTrustedIps(dto.workspaceId) }); + queryClient.invalidateQueries({ queryKey: trustedIps.getTrustedIps(dto.projectId) }); } }); }; diff --git a/frontend/src/hooks/api/types.ts b/frontend/src/hooks/api/types.ts index 8c29d4825..4b73eba28 100644 --- a/frontend/src/hooks/api/types.ts +++ b/frontend/src/hooks/api/types.ts @@ -7,8 +7,19 @@ export type { GetAuthTokenAPI } from "./auth/types"; export type { IncidentContact } from "./incidentContacts/types"; export type { IntegrationAuth } from "./integrationAuth/types"; export type { TCloudIntegration, TIntegration } from "./integrations/types"; -export type { UserWsKeyPair } from "./keys/types"; export type { Organization } from "./organization/types"; +export type { + CreateEnvironmentDTO, + CreateWorkspaceDTO, + DeleteEnvironmentDTO, + DeleteWorkspaceDTO, + Project, + ProjectEnv, + ProjectTag, + ToggleAutoCapitalizationDTO, + UpdateEnvironmentDTO, + UpdateProjectDTO +} from "./projects/types"; export type { TSecretApprovalPolicy } from "./secretApproval/types"; export type { TGetSecretApprovalRequestDetails, @@ -29,18 +40,6 @@ export type { SubscriptionPlan } from "./subscriptions/types"; export type { WsTag } from "./tags/types"; export type { OrgUser, TWorkspaceUser, User, UserEnc } from "./users/types"; export type { TWebhook } from "./webhooks/types"; -export type { - CreateEnvironmentDTO, - CreateWorkspaceDTO, - DeleteEnvironmentDTO, - DeleteWorkspaceDTO, - ToggleAutoCapitalizationDTO, - UpdateEnvironmentDTO, - UpdateProjectDTO, - Workspace, - WorkspaceEnv, - WorkspaceTag -} from "./workspace/types"; export enum ApiErrorTypes { ValidationError = "ValidationFailure", diff --git a/frontend/src/hooks/api/users/mutation.tsx b/frontend/src/hooks/api/users/mutation.tsx index 1f3fdf3ad..7acfb8fe0 100644 --- a/frontend/src/hooks/api/users/mutation.tsx +++ b/frontend/src/hooks/api/users/mutation.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace"; +import { projectKeys } from "../projects"; import { userKeys } from "./query-keys"; import { AddUserToWsDTONonE2EE } from "./types"; @@ -11,14 +11,14 @@ export const useAddUserToWsNonE2EE = () => { return useMutation({ mutationFn: async ({ projectId, usernames, roleSlugs }) => { - const { data } = await apiRequest.post(`/api/v2/workspace/${projectId}/memberships`, { + const { data } = await apiRequest.post(`/api/v1/projects/${projectId}/memberships`, { usernames, roleSlugs }); return data; }, onSuccess: (_, { orgId, projectId }) => { - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceUsers(projectId) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectUsers(projectId) }); queryClient.invalidateQueries({ queryKey: userKeys.allOrgMembershipProjectMemberships(orgId) }); diff --git a/frontend/src/hooks/api/users/queries.tsx b/frontend/src/hooks/api/users/queries.tsx index 77289fee6..2c0125361 100644 --- a/frontend/src/hooks/api/users/queries.tsx +++ b/frontend/src/hooks/api/users/queries.tsx @@ -8,9 +8,9 @@ import { queryClient as qc } from "@app/hooks/api/reactQuery"; import { APIKeyDataV2 } from "../apiKeys/types"; import { MfaMethod } from "../auth/types"; import { TGroupWithProjectMemberships } from "../groups/types"; +import { projectKeys } from "../projects"; import { setAuthToken } from "../reactQuery"; import { subscriptionQueryKeys } from "../subscriptions/queries"; -import { workspaceKeys } from "../workspace"; import { userKeys } from "./query-keys"; import { AddUserToOrgDTO, @@ -197,10 +197,10 @@ export const useAddUsersToOrg = () => { projects?.forEach((project) => { if (project.slug) { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceGroupMemberships(project.slug) + queryKey: projectKeys.getProjectGroupMemberships(project.slug) }); } - queryClient.invalidateQueries({ queryKey: workspaceKeys.getWorkspaceUsers(project.id) }); + queryClient.invalidateQueries({ queryKey: projectKeys.getProjectUsers(project.id) }); }); } }); diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index 5a90d4b64..a59965dfc 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -1,5 +1,5 @@ import { MfaMethod } from "../auth/types"; -import { ProjectType, ProjectUserMembershipTemporaryMode } from "../workspace/types"; +import { ProjectType, ProjectUserMembershipTemporaryMode } from "../projects/types"; export enum AuthMethod { EMAIL = "email", diff --git a/frontend/src/hooks/api/webhooks/mutation.tsx b/frontend/src/hooks/api/webhooks/mutation.tsx index 10d5e472e..66eb8ae17 100644 --- a/frontend/src/hooks/api/webhooks/mutation.tsx +++ b/frontend/src/hooks/api/webhooks/mutation.tsx @@ -13,8 +13,8 @@ export const useCreateWebhook = () => { const { data } = await apiRequest.post("/api/v1/webhooks", dto); return data; }, - onSuccess: (_, { workspaceId }) => { - queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(workspaceId) }); + onSuccess: (_, { projectId }) => { + queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(projectId) }); } }); }; @@ -27,11 +27,11 @@ export const useTestWebhook = () => { const { data } = await apiRequest.post(`/api/v1/webhooks/${webhookId}/test`); return data; }, - onSuccess: (_, { workspaceId }) => { - queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(workspaceId) }); + onSuccess: (_, { projectId }) => { + queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(projectId) }); }, - onError: (_, { workspaceId }) => { - queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(workspaceId) }); + onError: (_, { projectId }) => { + queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(projectId) }); } }); }; @@ -46,8 +46,8 @@ export const useUpdateWebhook = () => { }); return data; }, - onSuccess: (_, { workspaceId }) => { - queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(workspaceId) }); + onSuccess: (_, { projectId }) => { + queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(projectId) }); } }); }; @@ -60,8 +60,8 @@ export const useDeleteWebhook = () => { const { data } = await apiRequest.delete(`/api/v1/webhooks/${dto.webhookId}`); return data; }, - onSuccess: (_, { workspaceId }) => { - queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(workspaceId) }); + onSuccess: (_, { projectId }) => { + queryClient.invalidateQueries({ queryKey: queryKeys.getWebhooks(projectId) }); } }); }; diff --git a/frontend/src/hooks/api/webhooks/query.tsx b/frontend/src/hooks/api/webhooks/query.tsx index fc1840409..3f92a9695 100644 --- a/frontend/src/hooks/api/webhooks/query.tsx +++ b/frontend/src/hooks/api/webhooks/query.tsx @@ -8,19 +8,19 @@ export const queryKeys = { getWebhooks: (workspaceId: string) => ["webhooks", { workspaceId }] }; -const fetchWebhooks = async (workspaceId: string) => { +const fetchWebhooks = async (projectId: string) => { const { data } = await apiRequest.get<{ webhooks: TWebhook[] }>("/api/v1/webhooks", { params: { - workspaceId + projectId } }); return data.webhooks; }; -export const useGetWebhooks = (workspaceId: string) => +export const useGetWebhooks = (projectId: string) => useQuery({ - queryKey: queryKeys.getWebhooks(workspaceId), - queryFn: () => fetchWebhooks(workspaceId), - enabled: Boolean(workspaceId) + queryKey: queryKeys.getWebhooks(projectId), + queryFn: () => fetchWebhooks(projectId), + enabled: Boolean(projectId) }); diff --git a/frontend/src/hooks/api/webhooks/types.ts b/frontend/src/hooks/api/webhooks/types.ts index 86183bf1b..7e2758ff8 100644 --- a/frontend/src/hooks/api/webhooks/types.ts +++ b/frontend/src/hooks/api/webhooks/types.ts @@ -23,7 +23,7 @@ export type TWebhook = { }; export type TCreateWebhookDto = { - workspaceId: string; + projectId: string; environment: string; webhookUrl: string; webhookSecretKey?: string; @@ -33,16 +33,16 @@ export type TCreateWebhookDto = { export type TUpdateWebhookDto = { webhookId: string; - workspaceId: string; + projectId: string; isDisabled?: boolean; }; export type TDeleteWebhookDto = { webhookId: string; - workspaceId: string; + projectId: string; }; export type TTestWebhookDTO = { webhookId: string; - workspaceId: string; + projectId: string; }; diff --git a/frontend/src/hooks/api/workflowIntegrations/mutation.tsx b/frontend/src/hooks/api/workflowIntegrations/mutation.tsx index 89c65f888..d362c7b82 100644 --- a/frontend/src/hooks/api/workflowIntegrations/mutation.tsx +++ b/frontend/src/hooks/api/workflowIntegrations/mutation.tsx @@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { workspaceKeys } from "../workspace/query-keys"; +import { projectKeys } from "../projects/query-keys"; import { workflowIntegrationKeys } from "./queries"; import { TCheckMicrosoftTeamsIntegrationInstallationStatusDTO, @@ -118,15 +118,15 @@ export const useUpdateProjectWorkflowIntegrationConfig = () => { return useMutation({ mutationFn: async (dto: TUpdateProjectWorkflowIntegrationConfigDTO) => { const { data } = await apiRequest.put( - `/api/v1/workspace/${dto.workspaceId}/workflow-integration`, + `/api/v1/projects/${dto.projectId}/workflow-integration`, dto ); return data; }, - onSuccess: (_, { workspaceId, integration }) => { + onSuccess: (_, { projectId: workspaceId, integration }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceWorkflowIntegrationConfig(workspaceId, integration) + queryKey: projectKeys.getProjectWorkflowIntegrationConfig(workspaceId, integration) }); } }); @@ -138,14 +138,14 @@ export const useDeleteProjectWorkflowIntegration = () => { return useMutation({ mutationFn: async (dto: TDeleteProjectWorkflowIntegrationDTO) => { const { data } = await apiRequest.delete( - `/api/v1/workspace/${dto.projectId}/workflow-integration/${dto.integration}/${dto.integrationId}` + `/api/v1/projects/${dto.projectId}/workflow-integration/${dto.integration}/${dto.integrationId}` ); return data; }, onSuccess: (_, { projectId, integration }) => { queryClient.invalidateQueries({ - queryKey: workspaceKeys.getWorkspaceWorkflowIntegrationConfig(projectId, integration) + queryKey: projectKeys.getProjectWorkflowIntegrationConfig(projectId, integration) }); } }); diff --git a/frontend/src/hooks/api/workflowIntegrations/types.ts b/frontend/src/hooks/api/workflowIntegrations/types.ts index 4d2baf4bf..668850124 100644 --- a/frontend/src/hooks/api/workflowIntegrations/types.ts +++ b/frontend/src/hooks/api/workflowIntegrations/types.ts @@ -106,7 +106,7 @@ export type ProjectWorkflowIntegrationConfig = export type TUpdateProjectWorkflowIntegrationConfigDTO = | { integration: WorkflowIntegrationPlatform.SLACK; - workspaceId: string; + projectId: string; integrationId: string; isAccessRequestNotificationEnabled: boolean; accessRequestChannels: string; @@ -115,7 +115,7 @@ export type TUpdateProjectWorkflowIntegrationConfigDTO = } | { integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS; - workspaceId: string; + projectId: string; integrationId: string; isAccessRequestNotificationEnabled: boolean; isSecretRequestNotificationEnabled: boolean; diff --git a/frontend/src/hooks/api/workspace/query-keys.tsx b/frontend/src/hooks/api/workspace/query-keys.tsx deleted file mode 100644 index aca6f48b7..000000000 --- a/frontend/src/hooks/api/workspace/query-keys.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { TListProjectIdentitiesDTO, TSearchProjectsDTO } from "@app/hooks/api/workspace/types"; - -import type { CaStatus } from "../ca"; -import { WorkflowIntegrationPlatform } from "../workflowIntegrations/types"; - -export const workspaceKeys = { - getWorkspaceById: (workspaceId: string) => ["workspaces", { workspaceId }] as const, - getWorkspaceSecrets: (workspaceId: string) => [{ workspaceId }, "workspace-secrets"] as const, - getWorkspaceIndexStatus: (workspaceId: string) => - [{ workspaceId }, "workspace-index-status"] as const, - getProjectUpgradeStatus: (workspaceId: string) => [{ workspaceId }, "workspace-upgrade-status"], - getWorkspaceMemberships: (orgId: string) => [{ orgId }, "workspace-memberships"], - getWorkspaceAuthorization: (workspaceId: string) => [{ workspaceId }, "workspace-authorizations"], - getWorkspaceIntegrations: (workspaceId: string) => [{ workspaceId }, "workspace-integrations"], - getAllUserWorkspace: () => ["workspaces"] as const, - getWorkspaceAuditLogs: (workspaceId: string) => - [{ workspaceId }, "workspace-audit-logs"] as const, - getWorkspaceUsers: ( - workspaceId: string, - includeGroupMembers: boolean = false, - roles: string[] = [] - ) => [{ workspaceId, includeGroupMembers, roles }, "workspace-users"] as const, - getWorkspaceUserDetails: (workspaceId: string, membershipId: string) => - [{ workspaceId, membershipId }, "workspace-user-details"] as const, - getWorkspaceIdentityMemberships: (workspaceId: string) => - [{ workspaceId }, "workspace-identity-memberships"] as const, - getWorkspaceIdentityMembershipDetails: (workspaceId: string, identityId: string) => - [{ workspaceId, identityId }, "workspace-identity-membership-details"] as const, - // allows invalidation using above key without knowing params - getWorkspaceIdentityMembershipsWithParams: ({ - workspaceId, - ...params - }: TListProjectIdentitiesDTO) => - [...workspaceKeys.getWorkspaceIdentityMemberships(workspaceId), params] as const, - searchWorkspace: (dto: TSearchProjectsDTO) => ["search-projects", dto] as const, - getWorkspaceGroupMemberships: (workspaceId: string) => - [{ workspaceId }, "workspace-groups"] as const, - getWorkspaceGroupMembershipDetails: (workspaceId: string, groupId: string) => - [{ workspaceId, groupId }, "workspace-group-membership-details"] as const, - getWorkspaceCas: ({ projectSlug }: { projectSlug: string }) => - [{ projectSlug }, "workspace-cas"] as const, - specificWorkspaceCas: ({ projectSlug, status }: { projectSlug: string; status?: CaStatus }) => - [...workspaceKeys.getWorkspaceCas({ projectSlug }), { status }] as const, - allWorkspaceCertificates: () => ["workspace-certificates"] as const, - forWorkspaceCertificates: (slug: string) => - [...workspaceKeys.allWorkspaceCertificates(), slug] as const, - specificWorkspaceCertificates: ({ - slug, - offset, - limit - }: { - slug: string; - offset: number; - limit: number; - }) => [...workspaceKeys.forWorkspaceCertificates(slug), { offset, limit }] as const, - getWorkspacePkiAlerts: (workspaceId: string) => - [{ workspaceId }, "workspace-pki-alerts"] as const, - getWorkspacePkiSubscribers: (projectId: string) => - [{ projectId }, "workspace-pki-subscribers"] as const, - getWorkspacePkiCollections: (workspaceId: string) => - [{ workspaceId }, "workspace-pki-collections"] as const, - getWorkspaceCertificateTemplates: (workspaceId: string) => - [{ workspaceId }, "workspace-certificate-templates"] as const, - getWorkspaceWorkflowIntegrationConfig: ( - workspaceId: string, - integration: WorkflowIntegrationPlatform - ) => [{ workspaceId, integration }, "workspace-workflow-integration-config"] as const, - getWorkspaceSshCas: (projectId: string) => [{ projectId }, "workspace-ssh-cas"] as const, - allWorkspaceSshCertificates: (projectId: string) => - [{ projectId }, "workspace-ssh-certificates"] as const, - getWorkspaceSshHosts: (projectId: string) => [{ projectId }, "workspace-ssh-hosts"] as const, - getWorkspaceSshHostGroups: (projectId: string) => - [{ projectId }, "workspace-ssh-host-groups"] as const, - specificWorkspaceSshCertificates: ({ - offset, - limit, - projectId - }: { - offset: number; - limit: number; - projectId: string; - }) => [...workspaceKeys.allWorkspaceSshCertificates(projectId), { offset, limit }] as const, - getWorkspaceSshCertificateTemplates: (projectId: string) => - [{ projectId }, "workspace-ssh-certificate-templates"] as const, - getProjectSshConfig: (projectId: string) => [{ projectId }, "project-ssh-config"] as const -}; diff --git a/frontend/src/hooks/useGetProjectTypeFromRoute.tsx b/frontend/src/hooks/useGetProjectTypeFromRoute.tsx index 3156216db..972671a96 100644 --- a/frontend/src/hooks/useGetProjectTypeFromRoute.tsx +++ b/frontend/src/hooks/useGetProjectTypeFromRoute.tsx @@ -1,7 +1,7 @@ import { useMemo } from "react"; import { useRouterState } from "@tanstack/react-router"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; export const useGetProjectTypeFromRoute = () => { const { location } = useRouterState(); diff --git a/frontend/src/hooks/usePathAccessPolicies.tsx b/frontend/src/hooks/usePathAccessPolicies.tsx index 1fbc5fd52..0ad25b0d2 100644 --- a/frontend/src/hooks/usePathAccessPolicies.tsx +++ b/frontend/src/hooks/usePathAccessPolicies.tsx @@ -1,6 +1,6 @@ import { useMemo } from "react"; -import { useSubscription, useWorkspace } from "@app/context"; +import { useProject, useSubscription } from "@app/context"; import { useGetAccessApprovalPolicies } from "@app/hooks/api"; const matchesPath = (folderPath: string, pattern: string) => { @@ -37,10 +37,10 @@ type Params = { }; export const usePathAccessPolicies = ({ secretPath, environment }: Params) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { subscription } = useSubscription(); const { data: policies } = useGetAccessApprovalPolicies({ - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, options: { enabled: subscription.secretApproval } diff --git a/frontend/src/layouts/KmsLayout/KmsLayout.tsx b/frontend/src/layouts/KmsLayout/KmsLayout.tsx index c34bc3626..285f3b7f8 100644 --- a/frontend/src/layouts/KmsLayout/KmsLayout.tsx +++ b/frontend/src/layouts/KmsLayout/KmsLayout.tsx @@ -4,12 +4,12 @@ import { Link, Outlet } from "@tanstack/react-router"; import { motion } from "framer-motion"; import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; export const KmsLayout = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { assumedPrivilegeDetails } = useProjectPermission(); return ( @@ -34,7 +34,7 @@ export const KmsLayout = () => { {({ isActive }) => ( @@ -51,7 +51,7 @@ export const KmsLayout = () => { {({ isActive }) => ( @@ -70,7 +70,7 @@ export const KmsLayout = () => { {({ isActive }) => ( @@ -87,7 +87,7 @@ export const KmsLayout = () => { {({ isActive }) => ( @@ -104,7 +104,7 @@ export const KmsLayout = () => { {({ isActive }) => ( diff --git a/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx b/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx index e9bb6a902..71be38b11 100644 --- a/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx +++ b/frontend/src/layouts/OrganizationLayout/components/NavBar/Navbar.tsx @@ -40,7 +40,7 @@ import { envConfig } from "@app/config/env"; import { useOrganization, useSubscription, useUser } from "@app/context"; import { isInfisicalCloud } from "@app/helpers/platform"; import { useToggle } from "@app/hooks"; -import { useGetOrganizations, useLogoutUser, workspaceKeys } from "@app/hooks/api"; +import { projectKeys, useGetOrganizations, useLogoutUser } from "@app/hooks/api"; import { authKeys, selectOrganization } from "@app/hooks/api/auth/queries"; import { MfaMethod } from "@app/hooks/api/auth/types"; import { getAuthToken } from "@app/hooks/api/reactQuery"; @@ -135,7 +135,7 @@ export const Navbar = () => { const handleOrgChange = async (orgId: string) => { queryClient.removeQueries({ queryKey: authKeys.getAuthToken }); - queryClient.removeQueries({ queryKey: workspaceKeys.getAllUserWorkspace() }); + queryClient.removeQueries({ queryKey: projectKeys.getAllUserProjects() }); const { token, isMfaEnabled, mfaMethod } = await selectOrganization({ organizationId: orgId diff --git a/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx b/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx index 4e17e4b17..ec4727330 100644 --- a/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx +++ b/frontend/src/layouts/PkiManagerLayout/PkiManagerLayout.tsx @@ -17,12 +17,12 @@ import { Link, Outlet } from "@tanstack/react-router"; import { motion } from "framer-motion"; import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; export const PkiManagerLayout = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { assumedPrivilegeDetails } = useProjectPermission(); const { t } = useTranslation(); @@ -49,7 +49,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -66,7 +66,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -83,7 +83,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -100,7 +100,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -117,7 +117,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -134,7 +134,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -153,7 +153,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -170,7 +170,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( @@ -187,7 +187,7 @@ export const PkiManagerLayout = () => { {({ isActive }) => ( diff --git a/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx b/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx index 995083ee7..754d80547 100644 --- a/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx +++ b/frontend/src/layouts/ProjectLayout/components/AssumePrivilegeModeBanner/AssumePrivilegeModeBanner.tsx @@ -2,13 +2,13 @@ import { faInfoCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { getProjectHomePage } from "@app/helpers/project"; import { useRemoveAssumeProjectPrivilege } from "@app/hooks/api"; import { ActorType } from "@app/hooks/api/auditLogs/enums"; export const AssumePrivilegeModeBanner = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const exitAssumePrivilegeMode = useRemoveAssumeProjectPrivilege(); const { assumedPrivilegeDetails } = useProjectPermission(); @@ -32,15 +32,12 @@ export const AssumePrivilegeModeBanner = () => { onClick={() => { exitAssumePrivilegeMode.mutate( { - projectId: currentWorkspace.id + projectId: currentProject.id }, { onSuccess: () => { - const url = getProjectHomePage( - currentWorkspace.type, - currentWorkspace.environments - ); - window.location.href = url.replace("$projectId", currentWorkspace.id); + const url = getProjectHomePage(currentProject.type, currentProject.environments); + window.location.href = url.replace("$projectId", currentProject.id); } } ); diff --git a/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx b/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx index ebc28a227..eb5b22938 100644 --- a/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx +++ b/frontend/src/layouts/ProjectLayout/components/ProjectSelect/ProjectSelect.tsx @@ -28,21 +28,21 @@ import { OrgPermissionActions, OrgPermissionSubjects, useOrganization, - useSubscription, - useWorkspace + useProject, + useSubscription } from "@app/context"; import { getProjectHomePage } from "@app/helpers/project"; import { usePopUp } from "@app/hooks"; -import { useGetUserWorkspaces } from "@app/hooks/api"; +import { useGetUserProjects } from "@app/hooks/api"; +import { Project } from "@app/hooks/api/projects/types"; import { useUpdateUserProjectFavorites } from "@app/hooks/api/users/mutation"; import { useGetUserProjectFavorites } from "@app/hooks/api/users/queries"; -import { Workspace } from "@app/hooks/api/workspace/types"; export const ProjectSelect = () => { const [searchProject, setSearchProject] = useState(""); - const { currentWorkspace } = useWorkspace(); + const { currentProject: currentWorkspace } = useProject(); const { currentOrg } = useOrganization(); - const { data: workspaces = [] } = useGetUserWorkspaces(); + const { data: projects = [] } = useGetUserProjects(); const { data: projectFavorites } = useGetUserProjectFavorites(currentOrg.id); const { subscription } = useSubscription(); @@ -86,16 +86,16 @@ export const ProjectSelect = () => { "upgradePlan" ] as const); - const projects = useMemo(() => { - const projectOptions = workspaces - .map((w): Workspace & { isFavorite: boolean } => ({ + const projectsSortedByFav = useMemo(() => { + const projectOptions = projects + .map((w): Project & { isFavorite: boolean } => ({ ...w, isFavorite: Boolean(projectFavorites?.includes(w.id)) })) .sort((a, b) => Number(b.isFavorite) - Number(a.isFavorite)); return projectOptions; - }, [workspaces, projectFavorites, currentWorkspace]); + }, [projects, projectFavorites, currentWorkspace]); return (
@@ -147,7 +147,7 @@ export const ProjectSelect = () => { />
- {projects + {projectsSortedByFav ?.filter((el) => el.name?.toLowerCase().includes(searchProject.toLowerCase())) ?.map((workspace) => { return ( @@ -200,16 +200,20 @@ export const ProjectSelect = () => {
- {(isAllowed) => ( - } - onClick={() => - handlePopUpOpen(isAddingProjectsAllowed ? "addNewWs" : "upgradePlan") - } - > - New Project - + {(isOldProjectPermissionAllowed) => ( + + {(isAllowed) => ( + } + onClick={() => + handlePopUpOpen(isAddingProjectsAllowed ? "addNewWs" : "upgradePlan") + } + > + New Project + + )} + )} diff --git a/frontend/src/layouts/SecretManagerLayout/SecretManagerLayout.tsx b/frontend/src/layouts/SecretManagerLayout/SecretManagerLayout.tsx index d85176a01..0b9b934c3 100644 --- a/frontend/src/layouts/SecretManagerLayout/SecretManagerLayout.tsx +++ b/frontend/src/layouts/SecretManagerLayout/SecretManagerLayout.tsx @@ -16,7 +16,7 @@ import { Link, Outlet, useLocation } from "@tanstack/react-router"; import { motion } from "framer-motion"; import { Badge, Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { useGetAccessRequestsCount, useGetSecretApprovalRequestCount, @@ -26,16 +26,15 @@ import { import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; export const SecretManagerLayout = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject, projectId } = useProject(); const { assumedPrivilegeDetails } = useProjectPermission(); const { t } = useTranslation(); - const workspaceId = currentWorkspace?.id || ""; - const projectSlug = currentWorkspace?.slug || ""; + const projectSlug = currentProject?.slug || ""; const location = useLocation(); const { data: secretApprovalReqCount } = useGetSecretApprovalRequestCount({ - workspaceId + projectId }); const { data: accessApprovalRequestCount } = useGetAccessRequestsCount({ projectSlug @@ -43,7 +42,7 @@ export const SecretManagerLayout = () => { // we only show the secret rotations v1 tab if they have existing rotations const { data: secretRotations } = useGetSecretRotations({ - workspaceId, + workspaceId: projectId, options: { refetchOnMount: false } @@ -75,9 +74,9 @@ export const SecretManagerLayout = () => { @@ -86,7 +85,7 @@ export const SecretManagerLayout = () => { isSelected={ isActive || location.pathname.startsWith( - `/projects/secret-management/${currentWorkspace.id}/overview` + `/projects/secret-management/${currentProject.id}/overview` ) } > @@ -102,7 +101,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( @@ -120,7 +119,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( @@ -138,7 +137,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( @@ -163,7 +162,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( @@ -182,7 +181,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( @@ -199,7 +198,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( @@ -216,7 +215,7 @@ export const SecretManagerLayout = () => { {({ isActive }) => ( diff --git a/frontend/src/layouts/SecretScanningLayout/SecretScanningLayout.tsx b/frontend/src/layouts/SecretScanningLayout/SecretScanningLayout.tsx index b84b33cab..af7bba5d1 100644 --- a/frontend/src/layouts/SecretScanningLayout/SecretScanningLayout.tsx +++ b/frontend/src/layouts/SecretScanningLayout/SecretScanningLayout.tsx @@ -14,9 +14,9 @@ import { motion } from "framer-motion"; import { Badge, Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; import { ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { ProjectPermissionSecretScanningFindingActions } from "@app/context/ProjectPermissionContext/types"; import { useGetSecretScanningUnresolvedFindingCount } from "@app/hooks/api/secretScanningV2"; @@ -24,14 +24,14 @@ import { useGetSecretScanningUnresolvedFindingCount } from "@app/hooks/api/secre import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; export const SecretScanningLayout = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { assumedPrivilegeDetails } = useProjectPermission(); const { permission } = useProjectPermission(); const { subscription } = useSubscription(); const { data: unresolvedFindings } = useGetSecretScanningUnresolvedFindingCount( - currentWorkspace.id, + currentProject.id, { enabled: subscription.secretScanning && @@ -65,7 +65,7 @@ export const SecretScanningLayout = () => { {({ isActive }) => ( @@ -82,7 +82,7 @@ export const SecretScanningLayout = () => { {({ isActive }) => ( @@ -104,7 +104,7 @@ export const SecretScanningLayout = () => { {({ isActive }) => ( @@ -123,7 +123,7 @@ export const SecretScanningLayout = () => { {({ isActive }) => ( @@ -140,7 +140,7 @@ export const SecretScanningLayout = () => { {({ isActive }) => ( @@ -157,7 +157,7 @@ export const SecretScanningLayout = () => { {({ isActive }) => ( diff --git a/frontend/src/layouts/SshLayout/SshLayout.tsx b/frontend/src/layouts/SshLayout/SshLayout.tsx index 9c807723e..92872ec1f 100644 --- a/frontend/src/layouts/SshLayout/SshLayout.tsx +++ b/frontend/src/layouts/SshLayout/SshLayout.tsx @@ -15,14 +15,14 @@ import { Lottie, Menu, MenuGroup, MenuItem } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { AssumePrivilegeModeBanner } from "../ProjectLayout/components/AssumePrivilegeModeBanner"; export const SshLayout = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { assumedPrivilegeDetails } = useProjectPermission(); return ( @@ -47,7 +47,7 @@ export const SshLayout = () => { {({ isActive }) => ( @@ -70,7 +70,7 @@ export const SshLayout = () => { {({ isActive }) => ( @@ -93,7 +93,7 @@ export const SshLayout = () => { {({ isActive }) => ( @@ -110,7 +110,7 @@ export const SshLayout = () => { {({ isActive }) => ( @@ -127,7 +127,7 @@ export const SshLayout = () => { {({ isActive }) => ( diff --git a/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertModal.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertModal.tsx index 04fafa0b2..5601e48db 100644 --- a/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertModal.tsx +++ b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertModal.tsx @@ -13,7 +13,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreatePkiAlert, useGetPkiAlertById, @@ -60,15 +60,15 @@ type Props = { }; export const PkiAlertModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: alert } = useGetPkiAlertById( (popUp?.pkiAlert?.data as { alertId: string })?.alertId || "" ); const { data: pkiCollections } = useListWorkspacePkiCollections({ - workspaceId: projectId + projectId }); const { mutateAsync: createPkiAlert } = useCreatePkiAlert(); diff --git a/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsSection.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsSection.tsx index 497f10c39..d3aeefab7 100644 --- a/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsSection.tsx +++ b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsSection.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, DeleteActionModal } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useDeletePkiAlert } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -12,8 +12,8 @@ import { PkiAlertModal } from "./PkiAlertModal"; import { PkiAlertsTable } from "./PkiAlertsTable"; export const PkiAlertsSection = () => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { mutateAsync: deletePkiAlert } = useDeletePkiAlert(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ diff --git a/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsTable.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsTable.tsx index b67c5a2c6..4ddbd4671 100644 --- a/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsTable.tsx +++ b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsTable.tsx @@ -10,7 +10,7 @@ import { THead, Tr } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useListWorkspacePkiAlerts } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -24,11 +24,11 @@ type Props = { }; export const PkiAlertsTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data, isPending } = useListWorkspacePkiAlerts({ - workspaceId: projectId + projectId }); return ( diff --git a/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionModal.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionModal.tsx index 366f51c62..5900a1ba9 100644 --- a/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionModal.tsx +++ b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionModal.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreatePkiCollection, useGetPkiCollectionById, @@ -28,8 +28,8 @@ type Props = { export const PkiCollectionModal = ({ popUp, handlePopUpToggle }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: pkiCollection } = useGetPkiCollectionById( (popUp?.pkiCollection?.data as { collectionId: string })?.collectionId || "" diff --git a/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionSection.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionSection.tsx index 81f5a8609..66732ad88 100644 --- a/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionSection.tsx +++ b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionSection.tsx @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, DeleteActionModal } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useDeletePkiCollection } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -12,8 +12,8 @@ import { PkiCollectionModal } from "./PkiCollectionModal"; import { PkiCollectionTable } from "./PkiCollectionTable"; export const PkiCollectionSection = () => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { mutateAsync: deletePkiCollection } = useDeletePkiCollection(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ diff --git a/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionTable.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionTable.tsx index ff525b1f4..ebd86973f 100644 --- a/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionTable.tsx +++ b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionTable.tsx @@ -19,7 +19,7 @@ import { THead, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useListWorkspacePkiCollections } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -32,11 +32,11 @@ type Props = { export const PkiCollectionTable = ({ handlePopUpOpen }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data, isPending } = useListWorkspacePkiCollections({ - workspaceId: projectId + projectId }); return ( diff --git a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx index 0bf3c4431..4e5859215 100644 --- a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx +++ b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx @@ -15,7 +15,7 @@ import { Tooltip } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { CaType, useDeleteCa, useGetCa } from "@app/hooks/api"; import { TInternalCertificateAuthority } from "@app/hooks/api/ca/types"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -30,7 +30,7 @@ import { } from "./components"; const Page = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const params = useParams({ from: ROUTE_PATHS.CertManager.CertAuthDetailsByIDPage.id @@ -38,11 +38,11 @@ const Page = () => { const { caName } = params as { caName: string }; const { data } = useGetCa({ caName, - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", type: CaType.INTERNAL }) as { data: TInternalCertificateAuthority }; - const projectId = currentWorkspace?.id || ""; + const projectId = currentProject?.id || ""; const { mutateAsync: deleteCa } = useDeleteCa(); @@ -55,11 +55,11 @@ const Page = () => { const onRemoveCaSubmit = async () => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; await deleteCa({ caName, - projectId: currentWorkspace.id, + projectId: currentProject.id, type: CaType.INTERNAL }); diff --git a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaDetailsSection.tsx b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaDetailsSection.tsx index f12fcfd28..9ee5c1b8b 100644 --- a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaDetailsSection.tsx +++ b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaDetailsSection.tsx @@ -4,7 +4,7 @@ import { format } from "date-fns"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, IconButton, Tooltip } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useTimedReset } from "@app/hooks"; import { CaStatus, CaType, InternalCaType, useGetCa } from "@app/hooks/api"; import { caStatusToNameMap, caTypeToNameMap } from "@app/hooks/api/ca/constants"; @@ -21,7 +21,7 @@ type Props = { }; export const CaDetailsSection = ({ caName, handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [copyTextId, isCopyingId, setCopyTextId] = useTimedReset({ initialState: "Copy ID to clipboard" }); @@ -31,7 +31,7 @@ export const CaDetailsSection = ({ caName, handlePopUpOpen }: Props) => { const { data } = useGetCa({ caName, - projectId: currentWorkspace.id, + projectId: currentProject.id, type: CaType.INTERNAL }); diff --git a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaRenewalModal.tsx b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaRenewalModal.tsx index 6f9cf3a1c..857586a58 100644 --- a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaRenewalModal.tsx +++ b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/components/CaRenewalModal.tsx @@ -13,7 +13,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaRenewalType, useRenewCa @@ -45,8 +45,8 @@ type Props = { }; export const CaRenewalModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectSlug = currentWorkspace?.slug || ""; + const { currentProject } = useProject(); + const projectSlug = currentProject?.slug || ""; const popUpData = popUp?.renewCa?.data as { caId: string; diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/ExternalCaInstallForm.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/ExternalCaInstallForm.tsx index 6f79cbb24..d737e6c45 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/ExternalCaInstallForm.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/ExternalCaInstallForm.tsx @@ -8,7 +8,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, IconButton, TextArea, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useTimedReset } from "@app/hooks"; import { useGetCaCsr, useImportCaCertificate } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -26,7 +26,7 @@ type Props = { }; export const ExternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [copyTextCaCsr, isCopyingCaCsr, setCopyTextCaCsr] = useTimedReset({ initialState: "Copy to clipboard" }); @@ -41,7 +41,7 @@ export const ExternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => { }); const { data: csr } = useGetCaCsr(caId); - const { mutateAsync: importCaCertificate } = useImportCaCertificate(currentWorkspace.id); + const { mutateAsync: importCaCertificate } = useImportCaCertificate(currentProject.id); useEffect(() => { reset(); @@ -49,11 +49,11 @@ export const ExternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => { const onFormSubmit = async ({ certificate, certificateChain }: FormData) => { try { - if (!csr || !caId || !currentWorkspace?.slug) return; + if (!csr || !caId || !currentProject?.slug) return; await importCaCertificate({ caId, - projectSlug: currentWorkspace?.slug, + projectSlug: currentProject?.slug, certificate, certificateChain }); diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/InternalCaInstallForm.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/InternalCaInstallForm.tsx index 677407dc8..5979d9711 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/InternalCaInstallForm.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/InternalCaInstallForm.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaStatus, useGetCaById, @@ -46,16 +46,16 @@ type Props = { }; export const InternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: cas } = useListWorkspaceCas({ - projectSlug: currentWorkspace?.slug ?? "", + projectId: currentProject.id, status: CaStatus.ACTIVE }); const { data: ca } = useGetCaById(caId); const { data: csr } = useGetCaCsr(caId); const { mutateAsync: signIntermediate } = useSignIntermediate(); - const { mutateAsync: importCaCertificate } = useImportCaCertificate(currentWorkspace.id); + const { mutateAsync: importCaCertificate } = useImportCaCertificate(currentProject.id); const { control, @@ -102,7 +102,7 @@ export const InternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => { const onFormSubmit = async ({ notAfter, maxPathLength }: FormData) => { try { - if (!csr || !caId || !currentWorkspace?.slug) return; + if (!csr || !caId || !currentProject?.slug) return; const { certificate, certificateChain } = await signIntermediate({ caId: parentCaId, @@ -114,7 +114,7 @@ export const InternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => { await importCaCertificate({ caId, - projectSlug: currentWorkspace?.slug, + projectSlug: currentProject?.slug, certificate, certificateChain }); diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaModal.tsx index d3040576f..2a976d682 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaModal.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaModal.tsx @@ -16,7 +16,7 @@ import { Switch // DatePicker } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaStatus, CaType, @@ -84,10 +84,10 @@ const caTypes = [ ]; export const CaModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: ca } = useGetCa({ caName: (popUp?.ca?.data as { name: string })?.name || "", - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", type: CaType.INTERNAL }); @@ -178,13 +178,13 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => { configuration }: FormData) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; if (ca) { // update await updateMutateAsync({ caName: ca.name, - projectId: currentWorkspace.id, + projectId: currentProject.id, name, type: CaType.INTERNAL, status, @@ -193,7 +193,7 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => { } else { // create await createMutateAsync({ - projectId: currentWorkspace.id, + projectId: currentProject.id, name, type, status, diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaSection.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaSection.tsx index 5de6027fa..ed4e8f847 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaSection.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaSection.tsx @@ -5,7 +5,7 @@ import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, DeleteActionModal } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { CaStatus, CaType, useDeleteCa, useUpdateCa } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -15,7 +15,7 @@ import { CaModal } from "./CaModal"; import { CaTable } from "./CaTable"; export const CaSection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: deleteCa } = useDeleteCa(); const { mutateAsync: updateCa } = useUpdateCa(); @@ -30,9 +30,9 @@ export const CaSection = () => { const onRemoveCaSubmit = async (caName: string) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; - await deleteCa({ caName, projectId: currentWorkspace.id, type: CaType.INTERNAL }); + await deleteCa({ caName, projectId: currentProject.id, type: CaType.INTERNAL }); createNotification({ text: "Successfully deleted CA", @@ -50,9 +50,9 @@ export const CaSection = () => { const onUpdateCaStatus = async ({ caName, status }: { caName: string; status: CaStatus }) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; - await updateCa({ caName, projectId: currentWorkspace.id, type: CaType.INTERNAL, status }); + await updateCa({ caName, projectId: currentProject.id, type: CaType.INTERNAL, status }); createNotification({ text: `Successfully ${status === CaStatus.ACTIVE ? "enabled" : "disabled"} CA`, diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaTable.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaTable.tsx index 00ab03625..81fce98c6 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaTable.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaTable.tsx @@ -22,7 +22,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { CaStatus, CaType, useListCasByTypeAndProjectId } from "@app/hooks/api"; import { caStatusToNameMap, @@ -49,8 +49,8 @@ type Props = { export const CaTable = ({ handlePopUpOpen }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useListCasByTypeAndProjectId(CaType.INTERNAL, currentWorkspace.id); + const { currentProject } = useProject(); + const { data, isPending } = useListCasByTypeAndProjectId(CaType.INTERNAL, currentProject.id); const cas = data as TInternalCertificateAuthority[]; return ( @@ -80,7 +80,7 @@ export const CaTable = ({ handlePopUpOpen }: Props) => { navigate({ to: "/projects/cert-management/$projectId/ca/$caName", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, caName: ca.name } }) diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx index 437837980..5e7ab5cdd 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx @@ -17,7 +17,7 @@ import { SelectItem, Switch } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { APP_CONNECTION_MAP } from "@app/helpers/appConnections"; import { TAvailableAppConnection, @@ -128,11 +128,11 @@ const caTypes = [ ]; export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: ca, isLoading: isCaLoading } = useGetCa({ caName: (popUp?.ca?.data as { name: string })?.name || "", - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", type: (popUp?.ca?.data as { type: CaType })?.type || "" }); @@ -202,17 +202,17 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { }, [popUp?.ca?.isOpen, popUp?.ca?.data, reset, ca]); const { data: availableRoute53Connections, isPending: isRoute53Pending } = - useListAvailableAppConnections(AppConnection.AWS, currentWorkspace.id, { + useListAvailableAppConnections(AppConnection.AWS, currentProject.id, { enabled: caType === CaType.ACME }); const { data: availableCloudflareConnections, isPending: isCloudflarePending } = - useListAvailableAppConnections(AppConnection.Cloudflare, currentWorkspace.id, { + useListAvailableAppConnections(AppConnection.Cloudflare, currentProject.id, { enabled: caType === CaType.ACME }); const { data: availableAzureConnections, isPending: isAzurePending } = - useListAvailableAppConnections(AppConnection.AzureADCS, currentWorkspace.id, { + useListAvailableAppConnections(AppConnection.AzureADCS, currentProject.id, { enabled: caType === CaType.AZURE_AD_CS }); @@ -298,7 +298,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { configuration: formConfiguration }: FormData) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; let configPayload: any; @@ -322,7 +322,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { if (ca) { await updateMutateAsync({ caName: ca.name, - projectId: currentWorkspace.id, + projectId: currentProject.id, name, type, status, @@ -331,7 +331,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => { }); } else { await createMutateAsync({ - projectId: currentWorkspace.id, + projectId: currentProject.id, name, type, status, diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx index c8d117e21..7e60b0373 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaSection.tsx @@ -5,7 +5,7 @@ import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, DeleteActionModal } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { CaStatus, CaType, useDeleteCa, useUpdateCa } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -13,7 +13,7 @@ import { ExternalCaModal } from "./ExternalCaModal"; import { ExternalCaTable } from "./ExternalCaTable"; export const ExternalCaSection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: deleteCa } = useDeleteCa(); const { mutateAsync: updateCa } = useUpdateCa(); @@ -26,9 +26,9 @@ export const ExternalCaSection = () => { const onRemoveCaSubmit = async (caName: string, type: CaType) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; - await deleteCa({ caName, type, projectId: currentWorkspace.id }); + await deleteCa({ caName, type, projectId: currentProject.id }); createNotification({ text: "Successfully deleted CA", @@ -54,9 +54,9 @@ export const ExternalCaSection = () => { status: CaStatus; }) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; - await updateCa({ caName: name, type, status, projectId: currentWorkspace.id }); + await updateCa({ caName: name, type, status, projectId: currentProject.id }); createNotification({ text: `Successfully ${status === CaStatus.ACTIVE ? "enabled" : "disabled"} CA`, diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx index e7b18f429..a948473e8 100644 --- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaTable.tsx @@ -26,7 +26,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { CaStatus, CaType, useListExternalCasByProjectId } from "@app/hooks/api"; import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -44,8 +44,8 @@ type Props = { }; export const ExternalCaTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useListExternalCasByProjectId(currentWorkspace.id); + const { currentProject } = useProject(); + const { data, isPending } = useListExternalCasByProjectId(currentProject.id); return (
diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateImportModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateImportModal.tsx index c4cffe7b0..70b51cbbe 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateImportModal.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateImportModal.tsx @@ -14,7 +14,7 @@ import { SelectItem, TextArea } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useGetCert, useImportCertificate, useListWorkspacePkiCollections } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -48,13 +48,13 @@ type TCertificateDetails = { export const CertificateImportModal = ({ popUp, handlePopUpToggle }: Props) => { const [certificateDetails, setCertificateDetails] = useState(null); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: cert } = useGetCert( (popUp?.certificateImport?.data as { serialNumber: string })?.serialNumber || "" ); const { data } = useListWorkspacePkiCollections({ - workspaceId: currentWorkspace?.id || "" + projectId: currentProject?.id || "" }); const { mutateAsync: importCertificate } = useImportCertificate(); @@ -76,10 +76,10 @@ export const CertificateImportModal = ({ popUp, handlePopUpToggle }: Props) => { collectionId }: FormData) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; const { serialNumber, certificate, certificateChain, privateKey } = await importCertificate({ - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, certificatePem, privateKeyPem, diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateModal.tsx index a10743023..a8509fe17 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateModal.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateModal.tsx @@ -22,7 +22,7 @@ import { SelectItem, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaStatus, useCreateCertificate, @@ -89,22 +89,22 @@ const CERT_TEMPLATE_NONE_VALUE = "none"; export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { const [certificateDetails, setCertificateDetails] = useState(null); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: cert } = useGetCert( (popUp?.certificate?.data as { serialNumber: string })?.serialNumber || "" ); const { data: cas } = useListWorkspaceCas({ - projectSlug: currentWorkspace?.slug ?? "", + projectId: currentProject.id, status: CaStatus.ACTIVE }); const { data } = useListWorkspacePkiCollections({ - workspaceId: currentWorkspace?.id || "" + projectId: currentProject?.id || "" }); const { data: templatesData } = useListWorkspaceCertificateTemplates({ - workspaceId: currentWorkspace?.id || "" + projectId: currentProject?.id || "" }); const { mutateAsync: createCertificate } = useCreateCertificate(); @@ -191,12 +191,12 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { extendedKeyUsages }: FormData) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; const { serialNumber, certificate, certificateChain, privateKey } = await createCertificate({ caId: !selectedCertTemplate ? caId : undefined, certificateTemplateId: selectedCertTemplate ? selectedCertTemplateId : undefined, - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, pkiCollectionId: collectionId, friendlyName, commonName, diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRevocationModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRevocationModal.tsx index 2f14fda3f..1d1539296 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRevocationModal.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRevocationModal.tsx @@ -4,7 +4,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Modal, ModalContent, Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useRevokeCert } from "@app/hooks/api"; import { crlReasons } from "@app/hooks/api/certificates/constants"; import { CrlReason } from "@app/hooks/api/certificates/enums"; @@ -35,7 +35,7 @@ type Props = { }; export const CertificateRevocationModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: revokeCertificate } = useRevokeCert(); const { @@ -49,12 +49,12 @@ export const CertificateRevocationModal = ({ popUp, handlePopUpToggle }: Props) const onFormSubmit = async ({ revocationReason }: FormData) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; const { serialNumber } = popUp.revokeCertificate.data as { serialNumber: string }; await revokeCertificate({ - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, serialNumber, revocationReason }); diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateModal.tsx index d709458f0..8f547e573 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateModal.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateModal.tsx @@ -22,7 +22,7 @@ import { SelectItem, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaStatus, useCreateCertTemplate, @@ -82,7 +82,7 @@ type Props = { }; export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: ca } = useGetCaById(caId); @@ -91,12 +91,12 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro ); const { data: cas } = useListWorkspaceCas({ - projectSlug: currentWorkspace?.slug ?? "", + projectId: currentProject?.id, status: CaStatus.ACTIVE }); const { data: collectionsData } = useListWorkspacePkiCollections({ - workspaceId: currentWorkspace?.id || "" + projectId: currentProject?.id || "" }); const { mutateAsync: createCertTemplate } = useCreateCertTemplate(); @@ -155,7 +155,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro keyUsages, extendedKeyUsages }: FormData) => { - if (!currentWorkspace?.id) { + if (!currentProject?.id) { return; } @@ -163,7 +163,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro if (certTemplate) { await updateCertTemplate({ id: certTemplate.id, - projectId: currentWorkspace.id, + projectId: currentProject.id, pkiCollectionId: collectionId, caId, name, @@ -184,7 +184,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro }); } else { await createCertTemplate({ - projectId: currentWorkspace.id, + projectId: currentProject.id, pkiCollectionId: collectionId, caId, name, diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesSection.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesSection.tsx index 0db7ba923..89f9780e8 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesSection.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesSection.tsx @@ -12,7 +12,7 @@ import { DeleteActionModal, IconButton } from "@app/components/v2"; import { ProjectPermissionPkiTemplateActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteCertTemplate } from "@app/hooks/api"; @@ -33,18 +33,18 @@ export const CertificateTemplatesSection = ({ caId }: Props) => { "upgradePlan" ] as const); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: deleteCertTemplate } = useDeleteCertTemplate(); const onRemoveCertificateTemplateSubmit = async (id: string) => { - if (!currentWorkspace?.id) { + if (!currentProject?.id) { return; } try { await deleteCertTemplate({ id, - projectId: currentWorkspace.id + projectId: currentProject.id }); createNotification({ diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx index 44ddbc8ba..696d07762 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx @@ -7,7 +7,7 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { ProjectPermissionCertificateActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { useDeleteCert } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -19,7 +19,7 @@ import { CertificateRevocationModal } from "./CertificateRevocationModal"; import { CertificatesTable } from "./CertificatesTable"; export const CertificatesSection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: deleteCert } = useDeleteCert(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ @@ -32,9 +32,9 @@ export const CertificatesSection = () => { const onRemoveCertificateSubmit = async (serialNumber: string) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; - await deleteCert({ serialNumber, projectSlug: currentWorkspace.slug }); + await deleteCert({ serialNumber, projectSlug: currentProject.slug }); createNotification({ text: "Successfully deleted certificate", diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx index 98f83bc02..3cf35ebd6 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx @@ -33,7 +33,7 @@ import { import { ProjectPermissionCertificateActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { useListWorkspaceCertificates } from "@app/hooks/api"; import { caSupportsCapability } from "@app/hooks/api/ca/constants"; @@ -62,15 +62,15 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(PER_PAGE_INIT); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data, isPending } = useListWorkspaceCertificates({ - projectSlug: currentWorkspace?.slug ?? "", + projectId: currentProject?.slug ?? "", offset: (page - 1) * perPage, limit: perPage }); // Fetch CA data to determine capabilities - const { data: caData } = useListCasByProjectId(currentWorkspace?.id ?? ""); + const { data: caData } = useListCasByProjectId(currentProject?.id ?? ""); // Create mapping from caId to CA type for capability checking const caCapabilityMap = useMemo(() => { diff --git a/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx b/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx index 0261d55fd..c53df83be 100644 --- a/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx +++ b/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx @@ -16,7 +16,7 @@ import { Tooltip } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useDeletePkiCollection, useGetPkiCollectionById } from "@app/hooks/api"; import { PkiItemType } from "@app/hooks/api/pkiCollections/constants"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -30,8 +30,8 @@ export const PkiCollectionPage = () => { from: ROUTE_PATHS.CertManager.PkiCollectionDetailsByIDPage.id }); const collectionId = params.collectionId as string; - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data } = useGetPkiCollectionById(collectionId); const { mutateAsync: deletePkiCollection } = useDeletePkiCollection(); diff --git a/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/components/AddPkiCollectionItemModal.tsx b/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/components/AddPkiCollectionItemModal.tsx index f356f2190..3bcc3dc31 100644 --- a/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/components/AddPkiCollectionItemModal.tsx +++ b/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/components/AddPkiCollectionItemModal.tsx @@ -4,7 +4,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Modal, ModalContent, Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaStatus, useAddItemToPkiCollection, @@ -41,15 +41,15 @@ export const AddPkiCollectionItemModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: cas } = useListWorkspaceCas({ - projectSlug: currentWorkspace?.slug || "", + projectId: currentProject?.id || "", status: CaStatus.ACTIVE }); const { data } = useListWorkspaceCertificates({ - projectSlug: currentWorkspace?.slug || "", + projectId: currentProject?.slug || "", offset: 0, limit: 25 }); diff --git a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/PkiSubscriberDetailsByIDPage.tsx b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/PkiSubscriberDetailsByIDPage.tsx index 04db9861b..d7d44d4b5 100644 --- a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/PkiSubscriberDetailsByIDPage.tsx +++ b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/PkiSubscriberDetailsByIDPage.tsx @@ -19,7 +19,7 @@ import { ROUTE_PATHS } from "@app/const/routes"; import { ProjectPermissionPkiSubscriberActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { useDeletePkiSubscriber, useGetPkiSubscriber } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -29,8 +29,8 @@ import { PkiSubscriberCertificatesSection, PkiSubscriberDetailsSection } from ". const Page = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const subscriberName = useParams({ from: ROUTE_PATHS.CertManager.PkiSubscriberDetailsByIDPage.id, select: (el) => el.subscriberName diff --git a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx index 62e7337bd..d3533d71d 100644 --- a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx +++ b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx @@ -27,8 +27,8 @@ import { import { ProjectPermissionPkiSubscriberActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { useGetPkiSubscriberCertificates } from "@app/hooks/api"; import { caSupportsCapability } from "@app/hooks/api/ca/constants"; @@ -45,8 +45,8 @@ type Props = { const PER_PAGE_INIT = 25; export const PkiSubscriberCertificatesTable = ({ subscriberName, handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const { permission } = useProjectPermission(); const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(PER_PAGE_INIT); @@ -64,7 +64,7 @@ export const PkiSubscriberCertificatesTable = ({ subscriberName, handlePopUpOpen ); // Fetch CA data to determine capabilities - const { data: caData } = useListCasByProjectId(currentWorkspace.id); + const { data: caData } = useListCasByProjectId(currentProject.id); // Create mapping from caId to CA type for capability checking const caCapabilityMap = useMemo(() => { diff --git a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberDetailsSection.tsx b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberDetailsSection.tsx index 1f15982a4..bb928dcc2 100644 --- a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberDetailsSection.tsx +++ b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberDetailsSection.tsx @@ -16,8 +16,8 @@ import { import { ProjectPermissionPkiSubscriberActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { useTimedReset } from "@app/hooks"; import { @@ -44,8 +44,8 @@ type TCertificateDetails = { }; export const PkiSubscriberDetailsSection = ({ subscriberName, handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const { permission } = useProjectPermission(); const [certificateDetails, setCertificateDetails] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); diff --git a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx index f6deb97cb..932f3201b 100644 --- a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx +++ b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx @@ -22,7 +22,7 @@ import { TabPanel, Tabs } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { CaType, useCreatePkiSubscriber, @@ -158,8 +158,8 @@ const schema = z export type FormData = z.infer; export const PkiSubscriberModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const { data: subscribers } = useListWorkspacePkiSubscribers(projectId); const { data: cas } = useListCasByProjectId(projectId); const [tabValue, setTabValue] = useState(FormTab.Configuration); diff --git a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberSection.tsx b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberSection.tsx index f81636e49..f9680af9b 100644 --- a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberSection.tsx +++ b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberSection.tsx @@ -7,7 +7,7 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { ProjectPermissionPkiSubscriberActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { useDeletePkiSubscriber, useUpdatePkiSubscriber } from "@app/hooks/api"; import { PkiSubscriberStatus } from "@app/hooks/api/pkiSubscriber/types"; @@ -17,8 +17,8 @@ import { PkiSubscriberModal } from "./PkiSubscriberModal"; import { PkiSubscribersTable } from "./PkiSubscribersTable"; export const PkiSubscriberSection = () => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const { mutateAsync: deletePkiSubscriber } = useDeletePkiSubscriber(); const { mutateAsync: updatePkiSubscriber } = useUpdatePkiSubscriber(); @@ -55,7 +55,7 @@ export const PkiSubscriberSection = () => { status: PkiSubscriberStatus; }) => { try { - if (!currentWorkspace?.slug) return; + if (!currentProject?.slug) return; await updatePkiSubscriber({ subscriberName, projectId, status }); diff --git a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscribersTable.tsx b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscribersTable.tsx index d649c43a7..d28c2d3a2 100644 --- a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscribersTable.tsx +++ b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscribersTable.tsx @@ -30,7 +30,7 @@ import { import { ProjectPermissionPkiSubscriberActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { useListWorkspacePkiSubscribers } from "@app/hooks/api"; import { @@ -49,8 +49,8 @@ type Props = { export const PkiSubscribersTable = ({ handlePopUpOpen }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useListWorkspacePkiSubscribers(currentWorkspace?.id || ""); + const { currentProject } = useProject(); + const { data, isPending } = useListWorkspacePkiSubscribers(currentProject?.id || ""); return (
@@ -77,7 +77,7 @@ export const PkiSubscribersTable = ({ handlePopUpOpen }: Props) => { navigate({ to: "/projects/cert-management/$projectId/subscribers/$subscriberName", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, subscriberName: subscriber.name } }) diff --git a/frontend/src/pages/cert-manager/PkiTemplateListPage/PkiTemplateListPage.tsx b/frontend/src/pages/cert-manager/PkiTemplateListPage/PkiTemplateListPage.tsx index 4449e9a97..2ffe68813 100644 --- a/frontend/src/pages/cert-manager/PkiTemplateListPage/PkiTemplateListPage.tsx +++ b/frontend/src/pages/cert-manager/PkiTemplateListPage/PkiTemplateListPage.tsx @@ -42,8 +42,8 @@ import { import { ProjectPermissionPkiTemplateActions, ProjectPermissionSub, - useSubscription, - useWorkspace + useProject, + useSubscription } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteCertTemplateV2 } from "@app/hooks/api"; @@ -55,7 +55,7 @@ import { PkiTemplateForm } from "./components/PkiTemplateForm"; const PER_PAGE_INIT = 25; export const PkiTemplateListPage = () => { const { t } = useTranslation(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(PER_PAGE_INIT); const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ @@ -68,7 +68,7 @@ export const PkiTemplateListPage = () => { const { subscription } = useSubscription(); const { data, isPending } = useListCertificateTemplates({ - projectId: currentWorkspace.id, + projectId: currentProject.id, offset: (page - 1) * perPage, limit: perPage }); @@ -78,7 +78,7 @@ export const PkiTemplateListPage = () => { const onRemovePkiSubscriberSubmit = async () => { try { const pkiTemplate = await deleteCertTemplate.mutateAsync({ - projectId: currentWorkspace.id, + projectId: currentProject.id, templateName: popUp?.deleteTemplate?.data?.name }); diff --git a/frontend/src/pages/cert-manager/PkiTemplateListPage/components/PkiTemplateForm.tsx b/frontend/src/pages/cert-manager/PkiTemplateListPage/components/PkiTemplateForm.tsx index f52c83725..b8cdbfe1c 100644 --- a/frontend/src/pages/cert-manager/PkiTemplateListPage/components/PkiTemplateForm.tsx +++ b/frontend/src/pages/cert-manager/PkiTemplateListPage/components/PkiTemplateForm.tsx @@ -18,7 +18,7 @@ import { Input, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateCertTemplateV2, useListCasByProjectId, @@ -72,9 +72,9 @@ type Props = { }; export const PkiTemplateForm = ({ certTemplate, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const { data: cas, isPending: isCaLoading } = useListCasByProjectId(currentWorkspace.id); + const { data: cas, isPending: isCaLoading } = useListCasByProjectId(currentProject.id); const { mutateAsync: createCertTemplate } = useCreateCertTemplateV2(); const { mutateAsync: updateCertTemplate } = useUpdateCertTemplateV2(); @@ -124,7 +124,7 @@ export const PkiTemplateForm = ({ certTemplate, handlePopUpToggle }: Props) => { extendedKeyUsages, ca }: FormData) => { - if (!currentWorkspace?.id) { + if (!currentProject?.id) { return; } @@ -132,7 +132,7 @@ export const PkiTemplateForm = ({ certTemplate, handlePopUpToggle }: Props) => { if (certTemplate) { await updateCertTemplate({ templateName: certTemplate.name, - projectId: currentWorkspace.id, + projectId: currentProject.id, caName: ca.name, name, commonName, @@ -152,7 +152,7 @@ export const PkiTemplateForm = ({ certTemplate, handlePopUpToggle }: Props) => { }); } else { await createCertTemplate({ - projectId: currentWorkspace.id, + projectId: currentProject.id, caName: ca.name, name, commonName, diff --git a/frontend/src/pages/cert-manager/layout.tsx b/frontend/src/pages/cert-manager/layout.tsx index 6b846909e..c8ec6a23b 100644 --- a/frontend/src/pages/cert-manager/layout.tsx +++ b/frontend/src/pages/cert-manager/layout.tsx @@ -1,9 +1,9 @@ import { createFileRoute } from "@tanstack/react-router"; import { BreadcrumbTypes } from "@app/components/v2"; -import { workspaceKeys } from "@app/hooks/api"; +import { projectKeys } from "@app/hooks/api"; +import { fetchProjectById } from "@app/hooks/api/projects/queries"; import { fetchUserProjectPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries"; -import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries"; import { PkiManagerLayout } from "@app/layouts/PkiManagerLayout"; import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect"; @@ -13,15 +13,15 @@ export const Route = createFileRoute( component: PkiManagerLayout, beforeLoad: async ({ params, context }) => { const project = await context.queryClient.ensureQueryData({ - queryKey: workspaceKeys.getWorkspaceById(params.projectId), - queryFn: () => fetchWorkspaceById(params.projectId) + queryKey: projectKeys.getProjectById(params.projectId), + queryFn: () => fetchProjectById(params.projectId) }); await context.queryClient.ensureQueryData({ queryKey: roleQueryKeys.getUserProjectPermissions({ - workspaceId: params.projectId + projectId: params.projectId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId: params.projectId }) + queryFn: () => fetchUserProjectPermissions({ projectId: params.projectId }) }); return { diff --git a/frontend/src/pages/kms/KmipPage/components/KmipClientModal.tsx b/frontend/src/pages/kms/KmipPage/components/KmipClientModal.tsx index 8c959c7b0..7abbee35f 100644 --- a/frontend/src/pages/kms/KmipPage/components/KmipClientModal.tsx +++ b/frontend/src/pages/kms/KmipPage/components/KmipClientModal.tsx @@ -13,7 +13,7 @@ import { ModalContent, TextArea } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateKmipClient, useUpdateKmipClient } from "@app/hooks/api/kmip"; import { KmipPermission, TKmipClient } from "@app/hooks/api/kmip/types"; @@ -60,8 +60,8 @@ type FormProps = Pick & { const KmipClientForm = ({ onComplete, kmipClient }: FormProps) => { const createKmipClient = useCreateKmipClient(); const updateKmipClient = useUpdateKmipClient(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const isUpdate = !!kmipClient; const { diff --git a/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx b/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx index bcc49b11a..5abad9f18 100644 --- a/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx +++ b/frontend/src/pages/kms/KmipPage/components/KmipClientTable.tsx @@ -39,9 +39,9 @@ import { import { ProjectPermissionKmipActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { getUserTablePreference, @@ -59,9 +59,9 @@ import { KmipClientCertificateModal } from "./KmipClientCertificateModal"; import { KmipClientModal } from "./KmipClientModal"; export const KmipClientTable = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const projectId = currentWorkspace?.id ?? ""; + const projectId = currentProject?.id ?? ""; const { offset, diff --git a/frontend/src/pages/kms/OverviewPage/components/CmekModal.tsx b/frontend/src/pages/kms/OverviewPage/components/CmekModal.tsx index c43b6c8d0..93c0102b1 100644 --- a/frontend/src/pages/kms/OverviewPage/components/CmekModal.tsx +++ b/frontend/src/pages/kms/OverviewPage/components/CmekModal.tsx @@ -14,7 +14,7 @@ import { SelectItem, TextArea } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { keyUsageDefaultOption, kmsKeyUsageOptions } from "@app/helpers/kms"; import { AllowedEncryptionKeyAlgorithms, @@ -49,8 +49,8 @@ type FormProps = Pick & { const CmekForm = ({ onComplete, cmek }: FormProps) => { const createCmek = useCreateCmek(); const updateCmek = useUpdateCmek(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const isUpdate = !!cmek; const { diff --git a/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx b/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx index e1a2fe789..b1a7c409c 100644 --- a/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx +++ b/frontend/src/pages/kms/OverviewPage/components/CmekTable.tsx @@ -49,8 +49,8 @@ import { ProjectPermissionActions, ProjectPermissionCmekActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { kmsKeyUsageOptions } from "@app/helpers/kms"; import { @@ -87,10 +87,10 @@ const getStatusBadgeProps = ( }; export const CmekTable = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { permission } = useProjectPermission(); - const projectId = currentWorkspace?.id ?? ""; + const projectId = currentProject?.id ?? ""; const { offset, diff --git a/frontend/src/pages/kms/layout.tsx b/frontend/src/pages/kms/layout.tsx index 60bc35ab7..f29a7627a 100644 --- a/frontend/src/pages/kms/layout.tsx +++ b/frontend/src/pages/kms/layout.tsx @@ -1,9 +1,9 @@ import { createFileRoute } from "@tanstack/react-router"; import { BreadcrumbTypes } from "@app/components/v2"; -import { workspaceKeys } from "@app/hooks/api"; +import { projectKeys } from "@app/hooks/api"; +import { fetchProjectById } from "@app/hooks/api/projects/queries"; import { fetchUserProjectPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries"; -import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries"; import { KmsLayout } from "@app/layouts/KmsLayout"; import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect"; @@ -13,15 +13,15 @@ export const Route = createFileRoute( component: KmsLayout, beforeLoad: async ({ params, context }) => { const project = await context.queryClient.ensureQueryData({ - queryKey: workspaceKeys.getWorkspaceById(params.projectId), - queryFn: () => fetchWorkspaceById(params.projectId) + queryKey: projectKeys.getProjectById(params.projectId), + queryFn: () => fetchProjectById(params.projectId) }); await context.queryClient.ensureQueryData({ queryKey: roleQueryKeys.getUserProjectPermissions({ - workspaceId: params.projectId + projectId: params.projectId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId: params.projectId }) + queryFn: () => fetchUserProjectPermissions({ projectId: params.projectId }) }); return { diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx index 7f751fc7d..c1c9f0b0a 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgMembersTab/components/OrgMembersSection/AddOrgMemberModal.tsx @@ -21,10 +21,10 @@ import { useAddUsersToOrg, useFetchServerStatus, useGetOrgRoles, - useGetUserWorkspaces + useGetUserProjects } from "@app/hooks/api"; +import { ProjectType, ProjectVersion } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { ProjectType, ProjectVersion } from "@app/hooks/api/workspace/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; import { OrgInviteLink } from "./OrgInviteLink"; @@ -76,7 +76,7 @@ export const AddOrgMemberModal = ({ const { data: organizationRoles } = useGetOrgRoles(currentOrg?.id ?? ""); const { data: serverDetails } = useFetchServerStatus(); const { mutateAsync: addUsersMutateAsync } = useAddUsersToOrg(); - const { data: projects, isPending: isProjectsLoading } = useGetUserWorkspaces({ + const { data: projects, isPending: isProjectsLoading } = useGetUserProjects({ includeRoles: true }); diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AddAppConnectionModal.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AddAppConnectionModal.tsx index bcea6b530..c52f89dc9 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AddAppConnectionModal.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AddAppConnectionModal.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { Modal, ModalContent } from "@app/components/v2"; import { TAppConnection } from "@app/hooks/api/appConnections"; import { AppConnection } from "@app/hooks/api/appConnections/enums"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { AppConnectionForm } from "./AppConnectionForm"; import { AppConnectionsSelect } from "./AppConnectionList"; diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionList.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionList.tsx index 3170ad07f..0137d5a9e 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionList.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionList.tsx @@ -9,7 +9,7 @@ import { APP_CONNECTION_MAP } from "@app/helpers/appConnections"; import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useAppConnectionOptions } from "@app/hooks/api/appConnections"; import { AppConnection } from "@app/hooks/api/appConnections/enums"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; type Props = { onSelect: (app: AppConnection) => void; diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx index 9b24312bc..91ad35d4a 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionsTable.tsx @@ -47,7 +47,7 @@ import { usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { TAppConnection, useListAppConnections } from "@app/hooks/api/appConnections"; import { AppConnection } from "@app/hooks/api/appConnections/enums"; import { OrderByDirection } from "@app/hooks/api/generic/types"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { AddAppConnectionModal } from "./AddAppConnectionModal"; import { AppConnectionRow } from "./AppConnectionRow"; diff --git a/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx b/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx index 715f9c0b2..40b2f973f 100644 --- a/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx +++ b/frontend/src/pages/organization/AuditLogsPage/components/LogsFilter.tsx @@ -21,7 +21,7 @@ import { SelectItem } from "@app/components/v2"; import { useOrganization } from "@app/context"; -import { useGetUserWorkspaces } from "@app/hooks/api"; +import { useGetUserProjects } from "@app/hooks/api"; import { eventToNameMap, secretEvents, @@ -29,7 +29,7 @@ import { } from "@app/hooks/api/auditLogs/constants"; import { EventType } from "@app/hooks/api/auditLogs/enums"; import { UserAgentType } from "@app/hooks/api/auth/types"; -import { Workspace } from "@app/hooks/api/workspace/types"; +import { Project } from "@app/hooks/api/projects/types"; import { LogFilterItem } from "./LogFilterItem"; import { auditLogFilterFormSchema, Presets, TAuditLogFilterFormData } from "./types"; @@ -44,7 +44,7 @@ type Props = { presets?: Presets; setFilter: (data: TAuditLogFilterFormData) => void; filter: TAuditLogFilterFormData; - project?: Workspace; + project?: Project; }; const getActiveFilterCount = (filter: TAuditLogFilterFormData) => { @@ -72,7 +72,7 @@ const getActiveFilterCount = (filter: TAuditLogFilterFormData) => { }; export const LogsFilter = ({ presets, setFilter, filter, project }: Props) => { - const { data: workspaces = [] } = useGetUserWorkspaces(); + const { data: workspaces = [] } = useGetUserProjects(); const { currentOrg } = useOrganization(); const workspacesInOrg = workspaces.filter((ws) => ws.orgId === currentOrg?.id); diff --git a/frontend/src/pages/organization/AuditLogsPage/components/LogsSection.tsx b/frontend/src/pages/organization/AuditLogsPage/components/LogsSection.tsx index 5bbb42d32..f1173447c 100644 --- a/frontend/src/pages/organization/AuditLogsPage/components/LogsSection.tsx +++ b/frontend/src/pages/organization/AuditLogsPage/components/LogsSection.tsx @@ -13,7 +13,7 @@ import { } from "@app/context"; import { Timezone } from "@app/helpers/datetime"; import { withPermission, withProjectPermission } from "@app/hoc"; -import { Workspace } from "@app/hooks/api/workspace/types"; +import { Project } from "@app/hooks/api/projects/types"; import { usePopUp } from "@app/hooks/usePopUp"; import { LogsDateFilter } from "./LogsDateFilter"; @@ -31,7 +31,7 @@ type Props = { refetchInterval?: number; showFilters?: boolean; pageView?: boolean; - project?: Workspace; + project?: Project; }; const LogsSectionComponent = ({ diff --git a/frontend/src/pages/organization/AuditLogsPage/components/types.tsx b/frontend/src/pages/organization/AuditLogsPage/components/types.tsx index 8e0ec9ba9..b1338be24 100644 --- a/frontend/src/pages/organization/AuditLogsPage/components/types.tsx +++ b/frontend/src/pages/organization/AuditLogsPage/components/types.tsx @@ -1,7 +1,7 @@ import { z } from "zod"; import { ActorType, EventType, UserAgentType } from "@app/hooks/api/auditLogs/enums"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; export enum AuditLogDateFilterType { Relative = "relative", diff --git a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityAddToProjectModal.tsx b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityAddToProjectModal.tsx index a0565d50d..2e5c7101c 100644 --- a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityAddToProjectModal.tsx +++ b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityAddToProjectModal.tsx @@ -17,7 +17,7 @@ import { useAddIdentityToWorkspace, useGetIdentityProjectMemberships, useGetProjectRoles, - useGetUserWorkspaces, + useGetUserProjects, useGetWorkspaceById } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -44,7 +44,7 @@ type Props = { const Content = ({ identityId, handlePopUpToggle }: Omit) => { const { currentOrg } = useOrganization(); - const { data: workspaces = [] } = useGetUserWorkspaces(); + const { data: workspaces = [] } = useGetUserProjects(); const { mutateAsync: addIdentityToWorkspace } = useAddIdentityToWorkspace(); const { @@ -77,7 +77,7 @@ const Content = ({ identityId, handlePopUpToggle }: Omit) => { const onFormSubmit = async ({ project: selectedProject, role }: FormData) => { try { await addIdentityToWorkspace({ - workspaceId: selectedProject.id, + projectId: selectedProject.id, identityId, role: role.slug || undefined }); diff --git a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx index 5b0aac0b7..1622962ea 100644 --- a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx +++ b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectRow.tsx @@ -8,7 +8,7 @@ import { createNotification } from "@app/components/notifications"; import { IconButton, Td, Tooltip, Tr } from "@app/components/v2"; import { getProjectBaseURL } from "@app/helpers/project"; import { formatProjectRoleName } from "@app/helpers/roles"; -import { useGetUserWorkspaces } from "@app/hooks/api"; +import { useGetUserProjects } from "@app/hooks/api"; import { IdentityMembership } from "@app/hooks/api/identities/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -31,7 +31,7 @@ export const IdentityProjectRow = ({ membership: { id, createdAt, identity, project, roles }, handlePopUpOpen }: Props) => { - const { data: workspaces } = useGetUserWorkspaces(); + const { data: workspaces } = useGetUserProjects(); const navigate = useNavigate(); const isAccessible = useMemo(() => { diff --git a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsSection.tsx b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsSection.tsx index 0ea97c4d3..321a84ccb 100644 --- a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsSection.tsx +++ b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/IdentityProjectsSection/IdentityProjectsSection.tsx @@ -25,7 +25,7 @@ export const IdentityProjectsSection = ({ identityId }: Props) => { try { await deleteMutateAsync({ identityId: id, - workspaceId: projectId + projectId }); createNotification({ diff --git a/frontend/src/pages/organization/ProjectsPage/components/AllProjectView.tsx b/frontend/src/pages/organization/ProjectsPage/components/AllProjectView.tsx index d5c91d810..f7d20e2b7 100644 --- a/frontend/src/pages/organization/ProjectsPage/components/AllProjectView.tsx +++ b/frontend/src/pages/organization/ProjectsPage/components/AllProjectView.tsx @@ -41,7 +41,7 @@ import { } from "@app/helpers/userTablePreferences"; import { useDebounce, usePagination, usePopUp, useResetPageHelper } from "@app/hooks"; import { useOrgAdminAccessProject, useSearchProjects } from "@app/hooks/api"; -import { ProjectType, Workspace, WorkspaceEnv } from "@app/hooks/api/workspace/types"; +import { Project, ProjectEnv, ProjectType } from "@app/hooks/api/projects/types"; import { ProjectListToggle, ProjectListView @@ -101,7 +101,7 @@ export const AllProjectView = ({ const handleAccessProject = async ( type: ProjectType, projectId: string, - environments: WorkspaceEnv[] + environments: ProjectEnv[] ) => { try { await orgAdminAccessProject.mutateAsync({ @@ -126,7 +126,7 @@ export const AllProjectView = ({ offset, totalCount: searchedProjects?.totalCount || 0 }); - const requestedWorkspaceDetails = (popUp.requestAccessConfirmation.data || {}) as Workspace; + const requestedWorkspaceDetails = (popUp.requestAccessConfirmation.data || {}) as Project; const handleToggleFilterByProjectType = (el: ProjectType) => setProjectTypeFilter((state) => (state === el ? undefined : el)); @@ -224,22 +224,26 @@ export const AllProjectView = ({
- {(isAllowed) => ( - + {(isOldProjectPermissionAllowed) => ( + + {(isAllowed) => ( + + )} + )}
diff --git a/frontend/src/pages/organization/ProjectsPage/components/MyProjectView.tsx b/frontend/src/pages/organization/ProjectsPage/components/MyProjectView.tsx index d63099273..46f520d41 100644 --- a/frontend/src/pages/organization/ProjectsPage/components/MyProjectView.tsx +++ b/frontend/src/pages/organization/ProjectsPage/components/MyProjectView.tsx @@ -39,11 +39,11 @@ import { setUserTablePreference } from "@app/helpers/userTablePreferences"; import { usePagination, useResetPageHelper } from "@app/hooks"; -import { useGetUserWorkspaces } from "@app/hooks/api"; +import { useGetUserProjects } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; +import { Project, ProjectType } from "@app/hooks/api/projects/types"; import { useUpdateUserProjectFavorites } from "@app/hooks/api/users/mutation"; import { useGetUserProjectFavorites } from "@app/hooks/api/users/queries"; -import { ProjectType, Workspace } from "@app/hooks/api/workspace/types"; import { ProjectListToggle, ProjectListView @@ -79,7 +79,7 @@ export const MyProjectView = ({ {} ); - const { data: workspaces = [], isPending: isWorkspaceLoading } = useGetUserWorkspaces(); + const { data: workspaces = [], isPending: isWorkspaceLoading } = useGetUserProjects(); const { setPage, perPage, @@ -136,7 +136,7 @@ export const MyProjectView = ({ const { workspacesWithFaveProp } = useMemo(() => { const workspacesWithFav = filteredWorkspaces - .map((w): Workspace & { isFavorite: boolean } => ({ + .map((w): Project & { isFavorite: boolean } => ({ ...w, isFavorite: Boolean(projectFavorites?.includes(w.id)) })) @@ -188,7 +188,7 @@ export const MyProjectView = ({ } }; - const renderProjectGridItem = (workspace: Workspace, isFavorite: boolean) => ( + const renderProjectGridItem = (workspace: Project, isFavorite: boolean) => ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
{ @@ -242,7 +242,7 @@ export const MyProjectView = ({

); - const renderProjectListItem = (workspace: Workspace, isFavorite: boolean, index: number) => ( + const renderProjectListItem = (workspace: Project, isFavorite: boolean, index: number) => ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events
{ @@ -480,22 +480,26 @@ export const MyProjectView = ({
- {(isAllowed) => ( - + {(isOldProjectV1Allowed) => ( + + {(isAllowed) => ( + + )} + )}
diff --git a/frontend/src/pages/organization/RoleByIDPage/components/OrgRoleModifySection.utils.ts b/frontend/src/pages/organization/RoleByIDPage/components/OrgRoleModifySection.utils.ts index 03b86f2ab..9c374d398 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/OrgRoleModifySection.utils.ts +++ b/frontend/src/pages/organization/RoleByIDPage/components/OrgRoleModifySection.utils.ts @@ -122,12 +122,11 @@ export const formSchema = z.object({ .refine((val) => val !== "custom", { message: "Cannot use custom as its a keyword" }), permissions: z .object({ - workspace: z + project: z .object({ create: z.boolean().optional() }) .optional(), - "audit-logs": auditLogsPermissionSchema, member: generalPermissionSchema, groups: groupPermissionSchema, @@ -162,7 +161,11 @@ export const rolePermission2Form = (permissions: TPermission[] = []) => { // i would have to write a if loop with both conditions same const formVal: Record = {}; permissions.forEach((permission) => { - const { subject, action } = permission; + const { action } = permission; + let { subject } = permission; + if (subject === OrgPermissionSubjects.Workspace) { + subject = OrgPermissionSubjects.Project; + } if (!formVal?.[subject]) formVal[subject] = {}; formVal[subject][action] = true; }); diff --git a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx index 2746e10bc..5f9041a29 100644 --- a/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx +++ b/frontend/src/pages/organization/RoleByIDPage/components/RolePermissionsSection/OrgRoleWorkspaceRow.tsx @@ -28,7 +28,7 @@ export const OrgRoleWorkspaceRow = ({ isEditable, control, setValue }: Props) => const rule = useWatch({ control, - name: "permissions.workspace" + name: "permissions.project" }); const selectedPermissionCategory = useMemo(() => { @@ -60,7 +60,7 @@ export const OrgRoleWorkspaceRow = ({ isEditable, control, setValue }: Props) => setIsCustom.off(); if (val === Permission.NoAccess) { - setValue("permissions.workspace", { create: false }, { shouldDirty: true }); + setValue("permissions.project", { create: false }, { shouldDirty: true }); } }; @@ -95,8 +95,8 @@ export const OrgRoleWorkspaceRow = ({ isEditable, control, setValue }: Props) => {PERMISSION_ACTIONS.map(({ action, label }) => { return ( ( , - | "workspace" + | "project" | "organization-admin-console" | "kmip" | "gateway" diff --git a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AuditLogStreamForm.tsx b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AuditLogStreamForm.tsx index 6de5a0ecf..f59ae23aa 100644 --- a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AuditLogStreamForm.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AuditLogStreamForm.tsx @@ -6,6 +6,7 @@ import { TAuditLogStream } from "@app/hooks/api/types"; import { DiscriminativePick } from "@app/types"; import { AuditLogStreamHeader } from "../components/AuditLogStreamHeader"; +import { AzureProviderAuditLogStreamForm } from "./AzureProviderAuditLogStreamForm"; import { CriblProviderAuditLogStreamForm } from "./CriblProviderAuditLogStreamForm"; import { CustomProviderAuditLogStreamForm } from "./CustomProviderAuditLogStreamForm"; import { DatadogProviderAuditLogStreamForm } from "./DatadogProviderAuditLogStreamForm"; @@ -45,6 +46,8 @@ const CreateForm = ({ provider, onComplete }: CreateFormProps) => { }; switch (provider) { + case LogProvider.Azure: + return ; case LogProvider.Cribl: return ; case LogProvider.Custom: @@ -86,6 +89,10 @@ const UpdateForm = ({ auditLogStream, onComplete }: UpdateFormProps) => { }; switch (auditLogStream.provider) { + case LogProvider.Azure: + return ( + + ); case LogProvider.Cribl: return ( diff --git a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AzureProviderAuditLogStreamForm.tsx b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AzureProviderAuditLogStreamForm.tsx new file mode 100644 index 000000000..131ea1c85 --- /dev/null +++ b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/AzureProviderAuditLogStreamForm.tsx @@ -0,0 +1,158 @@ +import { Controller, FormProvider, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { Button, FormControl, Input, ModalClose, SecretInput } from "@app/components/v2"; +import { LogProvider } from "@app/hooks/api/auditLogStreams/enums"; +import { TAzureProviderLogStream } from "@app/hooks/api/auditLogStreams/types/providers/azure-provider"; + +type Props = { + auditLogStream?: TAzureProviderLogStream; + onSubmit: (formData: FormData) => void; +}; + +const formSchema = z.object({ + provider: z.literal(LogProvider.Azure), + credentials: z.object({ + tenantId: z.string().trim().uuid(), + clientId: z.string().trim().uuid(), + clientSecret: z.string().trim().length(40), + dceUrl: z.string().trim().url().min(1).max(255), + dcrId: z + .string() + .trim() + .regex(/^dcr-[0-9a-f]{32}$/, "DCR ID must be in dcr-*** format"), + cltName: z.string().trim().min(1).max(255) + }) +}); + +type FormData = z.infer; + +export const AzureProviderAuditLogStreamForm = ({ auditLogStream, onSubmit }: Props) => { + const isUpdate = Boolean(auditLogStream); + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: auditLogStream ?? { + provider: LogProvider.Azure + } + }); + + const { + handleSubmit, + control, + formState: { isSubmitting, isDirty } + } = form; + + return ( + +
+ ( + + + + )} + /> + ( + + + + )} + /> + ( + + onChange(e.target.value)} + /> + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> +
+ + + + +
+ +
+ ); +}; diff --git a/frontend/src/pages/organization/SettingsPage/components/ExternalMigrationsTab/ExternalMigrationsTab.tsx b/frontend/src/pages/organization/SettingsPage/components/ExternalMigrationsTab/ExternalMigrationsTab.tsx index 6ca1a5c28..8c6d511b1 100644 --- a/frontend/src/pages/organization/SettingsPage/components/ExternalMigrationsTab/ExternalMigrationsTab.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/ExternalMigrationsTab/ExternalMigrationsTab.tsx @@ -1,9 +1,8 @@ import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { OrgPermissionCan } from "@app/components/permissions"; import { Button } from "@app/components/v2"; -import { OrgPermissionActions, OrgPermissionSubjects, useOrgPermission } from "@app/context"; +import { useOrgPermission } from "@app/context"; import { usePopUp } from "@app/hooks"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; @@ -15,52 +14,45 @@ export const ExternalMigrationsTab = () => { const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["selectImportPlatform"] as const); return ( - -
-
-
-

Import from external source

+
+
+
+

Import from external source

- + - -
-

Import data from another platform to Infisical.

- handlePopUpToggle("selectImportPlatform", state)} - /> +
- +

Import data from another platform to Infisical.

+ + handlePopUpToggle("selectImportPlatform", state)} + /> +
); }; diff --git a/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/EditProjectTemplate.tsx b/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/EditProjectTemplate.tsx index c3ecdfa79..08d350c9c 100644 --- a/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/EditProjectTemplate.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/EditProjectTemplateSection/components/EditProjectTemplate.tsx @@ -7,8 +7,8 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; import { getProjectTitle } from "@app/helpers/project"; import { usePopUp } from "@app/hooks"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { TProjectTemplate, useDeleteProjectTemplate } from "@app/hooks/api/projectTemplates"; -import { ProjectType } from "@app/hooks/api/workspace/types"; import { ProjectTemplateDetailsModal } from "../../ProjectTemplateDetailsModal"; import { ProjectTemplateEnvironmentsForm } from "./ProjectTemplateEnvironmentsForm"; diff --git a/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/ProjectTemplateDetailsModal.tsx b/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/ProjectTemplateDetailsModal.tsx index 3c5e138e3..ad4f2776a 100644 --- a/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/ProjectTemplateDetailsModal.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/ProjectTemplatesTab/components/ProjectTemplateDetailsModal.tsx @@ -15,12 +15,12 @@ import { TextArea } from "@app/components/v2"; import { getProjectLottieIcon } from "@app/helpers/project"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { TProjectTemplate, useCreateProjectTemplate, useUpdateProjectTemplate } from "@app/hooks/api/projectTemplates"; -import { ProjectType } from "@app/hooks/api/workspace/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ diff --git a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserAddToProjectModal.tsx b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserAddToProjectModal.tsx index bd19db761..572be1d81 100644 --- a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserAddToProjectModal.tsx +++ b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserAddToProjectModal.tsx @@ -9,9 +9,9 @@ import { useOrganization } from "@app/context"; import { useAddUserToWsNonE2EE, useGetOrgMembershipProjectMemberships, - useGetUserWorkspaces + useGetUserProjects } from "@app/hooks/api"; -import { ProjectVersion } from "@app/hooks/api/workspace/types"; +import { ProjectVersion } from "@app/hooks/api/projects/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; const schema = z @@ -34,7 +34,7 @@ type Props = { const UserAddToProjectModalChild = ({ membershipId, popUp, handlePopUpToggle }: Props) => { const { currentOrg } = useOrganization(); const orgId = currentOrg?.id || ""; - const { data: workspaces = [] } = useGetUserWorkspaces(); + const { data: workspaces = [] } = useGetUserProjects(); const { mutateAsync: addUserToWorkspaceNonE2EE } = useAddUserToWsNonE2EE(); diff --git a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectRow.tsx b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectRow.tsx index aac501fce..a7a88a72c 100644 --- a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectRow.tsx +++ b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectRow.tsx @@ -7,7 +7,7 @@ import { createNotification } from "@app/components/notifications"; import { IconButton, Td, Tooltip, Tr } from "@app/components/v2"; import { getProjectBaseURL } from "@app/helpers/project"; import { formatProjectRoleName } from "@app/helpers/roles"; -import { useGetUserWorkspaces } from "@app/hooks/api"; +import { useGetUserProjects } from "@app/hooks/api"; import { TWorkspaceUser } from "@app/hooks/api/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; import { OrgAccessControlTabSections } from "@app/types/org"; @@ -24,7 +24,7 @@ export const UserProjectRow = ({ membership: { id, project, user, roles }, handlePopUpOpen }: Props) => { - const { data: workspaces = [] } = useGetUserWorkspaces(); + const { data: workspaces = [] } = useGetUserProjects(); const navigate = useNavigate(); const isAccessible = useMemo(() => { diff --git a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsSection.tsx b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsSection.tsx index c93e1fa8b..e06ed390d 100644 --- a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsSection.tsx +++ b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserProjectsSection/UserProjectsSection.tsx @@ -32,7 +32,7 @@ export const UserProjectsSection = ({ membershipId }: Props) => { const handleRemoveUser = async (projectId: string, username: string) => { try { - await removeUserFromWorkspace({ workspaceId: projectId, usernames: [username], orgId }); + await removeUserFromWorkspace({ projectId, usernames: [username], orgId }); createNotification({ text: "Successfully removed user from project", type: "success" diff --git a/frontend/src/pages/project/AccessControlPage/AccessControlPage.tsx b/frontend/src/pages/project/AccessControlPage/AccessControlPage.tsx index 8bb007e88..9da8770d2 100644 --- a/frontend/src/pages/project/AccessControlPage/AccessControlPage.tsx +++ b/frontend/src/pages/project/AccessControlPage/AccessControlPage.tsx @@ -3,9 +3,9 @@ import { useTranslation } from "react-i18next"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { ProjectAccessControlTabs } from "@app/types/project"; import { @@ -18,7 +18,7 @@ import { const Page = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const selectedTab = useSearch({ strict: false, select: (el) => el.selectedTab @@ -26,15 +26,15 @@ const Page = () => { const updateSelectedTab = (tab: string) => { navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/access-management` as const, + to: `${getProjectBaseURL(currentProject.type)}/access-management` as const, search: (prev) => ({ ...prev, selectedTab: tab }), params: { - projectId: currentWorkspace.id + projectId: currentProject.id } }); }; - const isSecretManager = currentWorkspace.type === ProjectType.SecretManager; + const isSecretManager = currentProject.type === ProjectType.SecretManager; return (
diff --git a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupModal.tsx b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupModal.tsx index f909f92b4..a279bd1b0 100644 --- a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupModal.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupModal.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FilterableSelect, FormControl, Modal, ModalContent } from "@app/components/v2"; -import { useOrganization, useWorkspace } from "@app/context"; +import { useOrganization, useProject } from "@app/context"; import { useAddGroupToWorkspace, useGetOrganizationGroups, @@ -31,14 +31,14 @@ type Props = { const Content = ({ popUp, handlePopUpToggle }: Props) => { const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const orgId = currentOrg?.id || ""; const { data: groups } = useGetOrganizationGroups(orgId); - const { data: groupMemberships } = useListWorkspaceGroups(currentWorkspace?.id || ""); + const { data: groupMemberships } = useListWorkspaceGroups(currentProject?.id || ""); - const { data: roles } = useGetProjectRoles(currentWorkspace?.id || ""); + const { data: roles } = useGetProjectRoles(currentProject?.id || ""); const { mutateAsync: addGroupToWorkspaceMutateAsync } = useAddGroupToWorkspace(); @@ -64,7 +64,7 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => { const onFormSubmit = async ({ group, role }: FormData) => { try { await addGroupToWorkspaceMutateAsync({ - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", groupId: group.id, role: role.slug || undefined }); diff --git a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx index 91b6d3186..49ff350fd 100644 --- a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx @@ -24,13 +24,13 @@ import { Tag, Tooltip } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { formatProjectRoleName } from "@app/helpers/roles"; import { usePopUp } from "@app/hooks"; import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api"; import { TGroupMembership } from "@app/hooks/api/groups/types"; +import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/projects/types"; import { TProjectRole } from "@app/hooks/api/roles/types"; -import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types"; import { groupBy } from "@app/lib/fn/array"; const temporaryRoleFormSchema = z.object({ @@ -213,7 +213,7 @@ type FormProps = { }; const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [searchRoles, setSearchRoles] = useState(""); @@ -255,7 +255,7 @@ const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) => try { await updateGroupWorkspaceRole.mutateAsync({ - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", groupId, roles: selectedRoles }); @@ -373,11 +373,11 @@ export const GroupRoles = ({ className, popperContentProps }: TMemberRolesProp) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { popUp, handlePopUpToggle } = usePopUp(["editRole"] as const); const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles( - currentWorkspace?.id ?? "" + currentProject?.id ?? "" ); return ( diff --git a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsSection.tsx b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsSection.tsx index 5ba6082e1..ee23a5778 100644 --- a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsSection.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsSection.tsx @@ -8,8 +8,8 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, - useSubscription, - useWorkspace + useProject, + useSubscription } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteGroupFromWorkspace } from "@app/hooks/api"; @@ -19,7 +19,7 @@ import { GroupTable } from "./GroupsTable"; export const GroupsSection = () => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: deleteMutateAsync } = useDeleteGroupFromWorkspace(); @@ -44,7 +44,7 @@ export const GroupsSection = () => { try { await deleteMutateAsync({ groupId, - projectId: currentWorkspace?.id || "" + projectId: currentProject?.id || "" }); createNotification({ diff --git a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx index 9bd98084e..3ce5b4062 100644 --- a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx @@ -32,7 +32,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { getUserTablePreference, @@ -61,7 +61,7 @@ enum GroupsOrderBy { } export const GroupTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const { @@ -85,7 +85,7 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => { }; const { data: groupMemberships = [], isPending } = useListWorkspaceGroups( - currentWorkspace?.id || "" + currentProject?.id || "" ); const filteredGroupMemberships = useMemo(() => { @@ -159,9 +159,9 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => { onKeyDown={(evt) => { if (evt.key === "Enter") { navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/groups/$groupId` as const, + to: `${getProjectBaseURL(currentProject.type)}/groups/$groupId` as const, params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, groupId: id } }); @@ -169,9 +169,9 @@ export const GroupTable = ({ handlePopUpOpen }: Props) => { }} onClick={() => navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/groups/$groupId` as const, + to: `${getProjectBaseURL(currentProject.type)}/groups/$groupId` as const, params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, groupId: id } }) diff --git a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx index 5b6e773db..7fbe99934 100644 --- a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/IdentityTab.tsx @@ -45,7 +45,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { formatProjectRoleName } from "@app/helpers/roles"; import { @@ -57,7 +57,7 @@ import { withProjectPermission } from "@app/hoc"; import { usePagination, useResetPageHelper } from "@app/hooks"; import { useDeleteIdentityFromWorkspace, useGetWorkspaceIdentityMemberships } from "@app/hooks/api"; import { OrderByDirection } from "@app/hooks/api/generic/types"; -import { ProjectIdentityOrderBy } from "@app/hooks/api/workspace/types"; +import { ProjectIdentityOrderBy } from "@app/hooks/api/projects/types"; import { usePopUp } from "@app/hooks/usePopUp"; import { IdentityModal } from "./components/IdentityModal"; @@ -66,7 +66,7 @@ const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2; export const IdentityTab = withProjectPermission( () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject, projectId } = useProject(); const navigate = useNavigate(); const { @@ -92,11 +92,9 @@ export const IdentityTab = withProjectPermission( setUserTablePreference("projectIdentityTable", PreferenceKey.PerPage, newPerPage); }; - const workspaceId = currentWorkspace?.id ?? ""; - const { data, isPending, isFetching } = useGetWorkspaceIdentityMemberships( { - workspaceId: currentWorkspace?.id || "", + projectId, offset, limit, orderDirection, @@ -126,7 +124,7 @@ export const IdentityTab = withProjectPermission( try { await deleteMutateAsync({ identityId, - workspaceId + projectId }); createNotification({ @@ -261,9 +259,9 @@ export const IdentityTab = withProjectPermission( onKeyDown={(evt) => { if (evt.key === "Enter") { navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/identities/$identityId` as const, + to: `${getProjectBaseURL(currentProject.type)}/identities/$identityId` as const, params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, identityId: id } }); @@ -271,9 +269,9 @@ export const IdentityTab = withProjectPermission( }} onClick={() => navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/identities/$identityId` as const, + to: `${getProjectBaseURL(currentProject.type)}/identities/$identityId` as const, params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, identityId: id } }) diff --git a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/IdentityModal.tsx b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/IdentityModal.tsx index 1baf80b9b..7261ba839 100644 --- a/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/IdentityModal.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/IdentityTab/components/IdentityModal.tsx @@ -14,7 +14,7 @@ import { ModalContent, Spinner } from "@app/components/v2"; -import { useOrganization, useWorkspace } from "@app/context"; +import { useOrganization, useProject } from "@app/context"; import { useAddIdentityToWorkspace, useGetIdentityMembershipOrgs, @@ -37,10 +37,9 @@ type Props = { const Content = ({ popUp, handlePopUpToggle }: Props) => { const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); + const { projectId } = useProject(); const organizationId = currentOrg?.id || ""; - const workspaceId = currentWorkspace?.id || ""; const { data: identityMembershipOrgsData, isPending: isMembershipsLoading } = useGetIdentityMembershipOrgs({ @@ -49,12 +48,12 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => { }); const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships; const { data: identityMembershipsData } = useGetWorkspaceIdentityMemberships({ - workspaceId, + projectId, limit: 20000 // TODO: this is temp to preserve functionality for larger projects, will optimize in PR referenced above }); const identityMemberships = identityMembershipsData?.identityMemberships; - const { data: roles, isPending: isRolesLoading } = useGetProjectRoles(workspaceId); + const { data: roles, isPending: isRolesLoading } = useGetProjectRoles(projectId); const { mutateAsync: addIdentityToWorkspaceMutateAsync } = useAddIdentityToWorkspace(); @@ -80,7 +79,7 @@ const Content = ({ popUp, handlePopUpToggle }: Props) => { const onFormSubmit = async ({ identity, role }: FormData) => { try { await addIdentityToWorkspaceMutateAsync({ - workspaceId, + projectId, identityId: identity.id, role: role.slug || undefined }); diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx index d9c9a8718..cdf49cf12 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/AddMemberModal.tsx @@ -22,7 +22,7 @@ import { OrgPermissionSubjects, useOrganization, useOrgPermission, - useWorkspace + useProject } from "@app/context"; import { useAddUsersToOrg, @@ -30,8 +30,8 @@ import { useGetProjectRoles, useGetWorkspaceUsers } from "@app/hooks/api"; +import { ProjectVersion } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { ProjectVersion } from "@app/hooks/api/workspace/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; const addMemberFormSchema = z.object({ @@ -57,7 +57,7 @@ type Props = { export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { const { t } = useTranslation(); const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate({ from: "" }); const { permission } = useOrgPermission(); const requesterEmail = useSearch({ @@ -66,12 +66,12 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { }); const orgId = currentOrg?.id || ""; - const workspaceId = currentWorkspace?.id || ""; + const projectId = currentProject?.id || ""; - const { data: members } = useGetWorkspaceUsers(workspaceId); + const { data: members } = useGetWorkspaceUsers(projectId); const { data: orgUsers } = useGetOrgUsers(orgId); - const { data: roles } = useGetProjectRoles(currentWorkspace?.id || ""); + const { data: roles } = useGetProjectRoles(currentProject?.id || ""); const { control, @@ -94,7 +94,7 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { }, [requesterEmail]); const onAddMembers = async ({ orgMemberships, projectRoleSlugs }: TAddMemberForm) => { - if (!currentWorkspace) return; + if (!currentProject) return; if (!currentOrg?.id) return; const existingMembers = orgMemberships.filter((membership) => !membership.isNewInvitee); @@ -109,7 +109,7 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { if (!selectedMembers) return; try { - if (currentWorkspace.version === ProjectVersion.V1) { + if (currentProject.version === ProjectVersion.V1) { createNotification({ type: "error", text: "Please upgrade your project to invite new members to the project." @@ -146,8 +146,8 @@ export const AddMemberModal = ({ popUp, handlePopUpToggle }: Props) => { organizationRoleSlug: ProjectMembershipRole.Member, // only applies to new invites projects: [ { - slug: currentWorkspace.slug, - id: currentWorkspace.id, + slug: currentProject.slug, + id: currentProject.id, projectRoleSlug: projectRoleSlugs.map((role) => role.slug) } ] diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRbacSection.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRbacSection.tsx index d18f8715a..291a5b58b 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRbacSection.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRbacSection.tsx @@ -29,14 +29,14 @@ import { ProjectPermissionActions, ProjectPermissionMemberActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { useGetProjectRoles, useUpdateUserWorkspaceRole } from "@app/hooks/api"; +import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; import { TWorkspaceUser } from "@app/hooks/api/types"; -import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types"; const roleFormSchema = z.object({ roles: z @@ -64,9 +64,8 @@ type Props = { }; export const MemberRbacSection = ({ projectMember, onOpenUpgradeModal }: Props) => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; - const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(workspaceId); + const { projectId } = useProject(); + const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(projectId); const { permission } = useProjectPermission(); const isMemberEditDisabled = permission.cannot( ProjectPermissionMemberActions.Edit, @@ -130,7 +129,7 @@ export const MemberRbacSection = ({ projectMember, onOpenUpgradeModal }: Props) try { await updateMembershipRole.mutateAsync({ - workspaceId, + projectId, membershipId: projectMember.id, roles: sanitizedRoles }); diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRoleForm.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRoleForm.tsx index 735257293..187e1813a 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRoleForm.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/MemberRoleForm.tsx @@ -1,7 +1,7 @@ import { Link } from "@tanstack/react-router"; import { Alert, AlertDescription } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { TWorkspaceUser } from "@app/hooks/api/types"; @@ -12,7 +12,7 @@ type Props = { onOpenUpgradeModal: (title: string) => void; }; export const MemberRoleForm = ({ projectMember, onOpenUpgradeModal }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); return (
@@ -22,9 +22,9 @@ export const MemberRoleForm = ({ projectMember, onOpenUpgradeModal }: Props) => > diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx index 5dd439744..3e93ec392 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx @@ -43,8 +43,8 @@ import { ProjectPermissionActions, ProjectPermissionMemberActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { removeTrailingSlash } from "@app/helpers/string"; import { usePopUp } from "@app/hooks"; @@ -89,7 +89,7 @@ export const SpecificPrivilegeSecretForm = ({ secretPath?: string; onClose?: () => void; }) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ "deletePrivilege", @@ -129,7 +129,7 @@ export const SpecificPrivilegeSecretForm = ({ temporaryAccess: privilege } : { - environmentSlug: currentWorkspace.environments?.[0]?.slug, + environmentSlug: currentProject.environments?.[0]?.slug, secretPath: initialSecretPath, read: selectedActions.includes(ProjectPermissionActions.Read), edit: selectedActions.includes(ProjectPermissionActions.Edit), @@ -202,7 +202,7 @@ export const SpecificPrivilegeSecretForm = ({ // This is used for requesting access additional privileges, not directly creating a privilege! const handleRequestAccess = async (data: TSecretPermissionForm) => { if (!policies) return; - if (!currentWorkspace) { + if (!currentProject) { createNotification({ type: "error", text: "No workspace found.", @@ -253,7 +253,7 @@ export const SpecificPrivilegeSecretForm = ({ ...(data.temporaryAccess.isTemporary && { temporaryRange: data.temporaryAccess.temporaryRange }), - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, isTemporary: data.temporaryAccess.isTemporary, permissions: actions .filter(({ allowed }) => allowed) @@ -307,7 +307,7 @@ export const SpecificPrivilegeSecretForm = ({ position="popper" dropdownContainerClassName="max-w-none" > - {currentWorkspace?.environments?.map(({ slug, id, name }) => ( + {currentProject?.environments?.map(({ slug, id, name }) => ( {name} diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersSection.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersSection.tsx index a8ecde73a..da5616453 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersSection.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersSection.tsx @@ -9,7 +9,7 @@ import { ProjectPermissionActions, ProjectPermissionSub, useOrganization, - useWorkspace + useProject } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteUserFromWorkspace } from "@app/hooks/api"; @@ -19,7 +19,7 @@ import { MembersTable } from "./MembersTable"; export const MembersSection = () => { const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: removeUserFromWorkspace } = useDeleteUserFromWorkspace(); @@ -32,11 +32,11 @@ export const MembersSection = () => { const handleRemoveUser = async () => { const username = (popUp?.removeMember?.data as { username: string })?.username; if (!currentOrg?.id) return; - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; try { await removeUserFromWorkspace({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, usernames: [username], orgId: currentOrg.id }); diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx index 2cbe144ee..22eb50460 100644 --- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MembersTable.tsx @@ -44,12 +44,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { - ProjectPermissionActions, - ProjectPermissionSub, - useUser, - useWorkspace -} from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject, useUser } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { formatProjectRoleName } from "@app/helpers/roles"; import { @@ -81,7 +76,7 @@ type Filter = { }; export const MembersTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { user } = useUser(); const navigate = useNavigate(); const [filter, setFilter] = useState({ @@ -90,8 +85,8 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => { const filterRoles = useMemo(() => filter.roles, [filter.roles]); const userId = user?.id || ""; - const workspaceId = currentWorkspace?.id || ""; - const { data: projectRoles } = useGetProjectRoles(workspaceId); + const projectId = currentProject?.id || ""; + const { data: projectRoles } = useGetProjectRoles(projectId); const { search, @@ -116,7 +111,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => { }; const { data: members = [], isPending: isMembersLoading } = useGetWorkspaceUsers( - workspaceId, + projectId, undefined, filterRoles ); @@ -312,9 +307,9 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => { onKeyDown={(evt) => { if (evt.key === "Enter") { navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/members/$membershipId`, + to: `${getProjectBaseURL(currentProject.type)}/members/$membershipId`, params: { - projectId: workspaceId, + projectId, membershipId } }); @@ -322,9 +317,9 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => { }} onClick={() => navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/members/$membershipId`, + to: `${getProjectBaseURL(currentProject.type)}/members/$membershipId`, params: { - projectId: workspaceId, + projectId, membershipId } }) diff --git a/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx b/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx index 211f1d0e8..e7b3b10b8 100644 --- a/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/ProjectRoleListTab/components/ProjectRoleList/ProjectRoleList.tsx @@ -39,7 +39,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { isCustomProjectRole } from "@app/helpers/roles"; import { @@ -67,8 +67,8 @@ export const ProjectRoleList = () => { "deleteRole", "duplicateRole" ] as const); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: roles, isPending: isRolesLoading } = useGetProjectRoles(projectId); @@ -250,9 +250,9 @@ export const ProjectRoleList = () => { className="h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700" onClick={() => navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/roles/$roleSlug`, + to: `${getProjectBaseURL(currentProject.type)}/roles/$roleSlug`, params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, roleSlug: slug } }) @@ -292,9 +292,9 @@ export const ProjectRoleList = () => { onClick={(e) => { e.stopPropagation(); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/roles/$roleSlug`, + to: `${getProjectBaseURL(currentProject.type)}/roles/$roleSlug`, params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, roleSlug: slug } }); diff --git a/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/components/ServiceTokenSection/AddServiceTokenModal.tsx b/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/components/ServiceTokenSection/AddServiceTokenModal.tsx index 8264d47bf..d63b6bb9c 100644 --- a/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/components/ServiceTokenSection/AddServiceTokenModal.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/ServiceTokenTab/components/ServiceTokenSection/AddServiceTokenModal.tsx @@ -22,7 +22,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useToggle } from "@app/hooks"; import { useCreateServiceToken } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -70,7 +70,7 @@ type Props = { const ServiceTokenForm = () => { const { t } = useTranslation(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, @@ -81,7 +81,7 @@ const ServiceTokenForm = () => { scopes: [ { secretPath: "/", - environment: currentWorkspace?.environments?.[0]?.slug + environment: currentProject?.environments?.[0]?.slug } ] } @@ -111,7 +111,7 @@ const ServiceTokenForm = () => { const onFormSubmit = async ({ name, scopes, expiresIn, permissions }: FormData) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; const randomBytes = crypto.randomBytes(16).toString("hex"); @@ -122,7 +122,7 @@ const ServiceTokenForm = () => { scopes, expiresIn: Number(expiresIn), name, - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, randomBytes, permissions: Object.entries(permissions) .filter(([, permissionsValue]) => permissionsValue) @@ -172,7 +172,7 @@ const ServiceTokenForm = () => { ( { onValueChange={(e) => onChange(e)} className="w-full" > - {currentWorkspace?.environments.map(({ name, slug }) => ( + {currentProject?.environments.map(({ name, slug }) => ( {name} @@ -225,7 +225,7 @@ const ServiceTokenForm = () => { variant="outline_bg" onClick={() => append({ - environment: currentWorkspace?.environments?.[0]?.slug || "", + environment: currentProject?.environments?.[0]?.slug || "", secretPath: "" }) } @@ -334,7 +334,7 @@ const ServiceTokenForm = () => { export const AddServiceTokenModal = ({ popUp, handlePopUpToggle }: Props) => { const { t } = useTranslation(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); return ( { { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data, isPending } = useGetUserWsServiceTokens({ - workspaceID: currentWorkspace?.id || "" + workspaceID: currentProject?.id || "" }); const { diff --git a/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx b/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx index 36a8ffeb0..84fb69b83 100644 --- a/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx +++ b/frontend/src/pages/project/AppConnectionsPage/AppConnectionsPage.tsx @@ -1,7 +1,7 @@ import { Helmet } from "react-helmet"; import { PageHeader } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { ProjectPermissionAppConnectionActions, ProjectPermissionSub @@ -11,7 +11,7 @@ import { AppConnectionsTable } from "@app/pages/organization/AppConnections/AppC export const AppConnectionsPage = withProjectPermission( () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); return (
@@ -28,10 +28,7 @@ export const AppConnectionsPage = withProjectPermission( description="Manage project App Connections" /> - +
diff --git a/frontend/src/pages/project/AuditLogsPage/AuditLogsPage.tsx b/frontend/src/pages/project/AuditLogsPage/AuditLogsPage.tsx index 0c83b0520..1e9b1ad54 100644 --- a/frontend/src/pages/project/AuditLogsPage/AuditLogsPage.tsx +++ b/frontend/src/pages/project/AuditLogsPage/AuditLogsPage.tsx @@ -1,11 +1,11 @@ import { Helmet } from "react-helmet"; import { PageHeader } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { LogsSection } from "@app/pages/organization/AuditLogsPage/components"; export const AuditLogsPage = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); return (
@@ -19,7 +19,7 @@ export const AuditLogsPage = () => { title="Audit logs" description="Audit logs for security and compliance teams to monitor information access." /> - +
diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx index a3dfabcd0..d6bda7ea1 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx @@ -4,8 +4,8 @@ import { useParams } from "@tanstack/react-router"; import { ProjectPermissionCan } from "@app/components/permissions"; import { EmptyState, PageHeader, Spinner } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; -import { useGetWorkspaceGroupMembershipDetails } from "@app/hooks/api/workspace/queries"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; +import { useGetWorkspaceGroupMembershipDetails } from "@app/hooks/api/projects/queries"; import { GroupDetailsSection } from "./components/GroupDetailsSection"; import { GroupMembersSection } from "./components/GroupMembersSection"; @@ -16,10 +16,10 @@ const Page = () => { select: (el) => el.groupId as string }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: groupMembership, isPending } = useGetWorkspaceGroupMembershipDetails( - currentWorkspace.id, + currentProject.id, groupId ); diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupDetailsSection.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupDetailsSection.tsx index 90c327067..0689d674a 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupDetailsSection.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupDetailsSection.tsx @@ -14,7 +14,7 @@ import { IconButton } from "@app/components/v2"; import { CopyButton } from "@app/components/v2/CopyButton"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { usePopUp } from "@app/hooks"; import { useDeleteGroupFromWorkspace } from "@app/hooks/api"; @@ -31,14 +31,14 @@ export const GroupDetailsSection = ({ groupMembership }: Props) => { ] as const); const { mutateAsync: deleteMutateAsync } = useDeleteGroupFromWorkspace(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const onRemoveGroupSubmit = async () => { try { await deleteMutateAsync({ groupId: groupMembership.group.id, - projectId: currentWorkspace.id + projectId: currentProject.id }); createNotification({ @@ -47,9 +47,9 @@ export const GroupDetailsSection = ({ groupMembership }: Props) => { }); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/access-management`, + to: `${getProjectBaseURL(currentProject.type)}/access-management`, params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: "groups" diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx index 7d155ba43..1df989602 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/components/GroupMembersSection/GroupMembersTable.tsx @@ -23,7 +23,7 @@ import { THead, Tr } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { getProjectHomePage } from "@app/helpers/project"; import { getUserTablePreference, @@ -69,12 +69,12 @@ export const GroupMembersTable = ({ groupMembership }: Props) => { setUserTablePreference("projectGroupMembersTable", PreferenceKey.PerPage, newPerPage); }; - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: groupMemberships, isPending } = useListProjectGroupUsers({ id: groupMembership.group.id, groupSlug: groupMembership.group.slug, - projectId: currentWorkspace.id, + projectId: currentProject.id, offset, limit: perPage, search, @@ -127,7 +127,7 @@ export const GroupMembersTable = ({ groupMembership }: Props) => { { actorId: userId, actorType: ActorType.USER, - projectId: currentWorkspace.id + projectId: currentProject.id }, { onSuccess: () => { @@ -136,8 +136,8 @@ export const GroupMembersTable = ({ groupMembership }: Props) => { text: "User privilege assumption has started" }); - const url = getProjectHomePage(currentWorkspace.type, currentWorkspace.environments); - window.location.href = url.replace("$projectId", currentWorkspace.id); + const url = getProjectHomePage(currentProject.type, currentProject.environments); + window.location.href = url.replace("$projectId", currentProject.id); } } ); diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx index e1da4edab..993320e56 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/IdentityDetailsByIDPage.tsx @@ -18,7 +18,7 @@ import { ProjectPermissionActions, ProjectPermissionIdentityActions, ProjectPermissionSub, - useWorkspace + useProject } from "@app/context"; import { getProjectBaseURL, getProjectHomePage } from "@app/helpers/project"; import { usePopUp } from "@app/hooks"; @@ -38,12 +38,10 @@ const Page = () => { strict: false, select: (el) => el.identityId as string }); - const { currentWorkspace } = useWorkspace(); - - const workspaceId = currentWorkspace?.id || ""; + const { currentProject, projectId } = useProject(); const { data: identityMembershipDetails, isPending: isMembershipDetailsLoading } = - useGetWorkspaceIdentityMembershipDetails(workspaceId, identityId); + useGetWorkspaceIdentityMembershipDetails(projectId, identityId); const { mutateAsync: deleteMutateAsync, isPending: isDeletingIdentity } = useDeleteIdentityFromWorkspace(); @@ -59,7 +57,7 @@ const Page = () => { { actorId: identityId, actorType: ActorType.IDENTITY, - projectId: workspaceId + projectId }, { onSuccess: () => { @@ -67,8 +65,8 @@ const Page = () => { type: "success", text: "Identity privilege assumption has started" }); - const url = getProjectHomePage(currentWorkspace.type, currentWorkspace.environments); - window.location.href = url.replace("$projectId", currentWorkspace.id); + const url = getProjectHomePage(currentProject.type, currentProject.environments); + window.location.href = url.replace("$projectId", currentProject.id); } } ); @@ -78,7 +76,7 @@ const Page = () => { try { await deleteMutateAsync({ identityId, - workspaceId + projectId }); createNotification({ text: "Successfully removed identity from project", @@ -86,9 +84,9 @@ const Page = () => { }); handlePopUpClose("deleteIdentity"); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/access-management` as const, + to: `${getProjectBaseURL(currentProject.type)}/access-management` as const, params: { - projectId: workspaceId + projectId }, search: { selectedTab: "identities" diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx index fe574a32d..9b4be2cb8 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityProjectAdditionalPrivilegeSection/IdentityProjectAdditionalPrivilegeModifySection.tsx @@ -24,8 +24,8 @@ import { import { ProjectPermissionIdentityActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { useCreateIdentityProjectAdditionalPrivilege, @@ -78,8 +78,8 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({ isDisabled }: Props) => { const isCreate = !privilegeId; - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: privilegeDetails, isPending } = useGetIdentityProjectPrivilegeDetails({ identityId, projectId, @@ -225,7 +225,7 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({ > Save - +
diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx index 1fa98628e..eb8653acb 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleDetailsSection.tsx @@ -23,7 +23,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { formatProjectRoleName } from "@app/helpers/roles"; import { usePopUp } from "@app/hooks"; import { useUpdateIdentityWorkspaceRole } from "@app/hooks/api"; @@ -41,7 +41,7 @@ export const IdentityRoleDetailsSection = ({ identityMembershipDetails, isMembershipDetailsLoading }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ "deleteRole", "modifyRole" @@ -53,7 +53,7 @@ export const IdentityRoleDetailsSection = ({ try { const updatedRoles = identityMembershipDetails?.roles?.filter((el) => el.id !== id); await updateIdentityWorkspaceRole({ - workspaceId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", identityId: identityMembershipDetails.identity.id, roles: updatedRoles.map( ({ diff --git a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx index c5860ec11..d47f4a74e 100644 --- a/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx +++ b/frontend/src/pages/project/IdentityDetailsByIDPage/components/IdentityRoleDetailsSection/IdentityRoleModify.tsx @@ -29,13 +29,13 @@ import { ProjectPermissionActions, ProjectPermissionIdentityActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { useGetProjectRoles, useUpdateIdentityWorkspaceRole } from "@app/hooks/api"; import { IdentityMembership } from "@app/hooks/api/identities/types"; +import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types"; const roleFormSchema = z.object({ roles: z @@ -62,9 +62,8 @@ type Props = { }; export const IdentityRoleModify = ({ identityProjectMembership }: Props) => { - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; - const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(workspaceId); + const { projectId } = useProject(); + const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(projectId); const { permission } = useProjectPermission(); const isIdentityEditDisabled = permission.cannot( ProjectPermissionIdentityActions.Edit, @@ -117,7 +116,7 @@ export const IdentityRoleModify = ({ identityProjectMembership }: Props) => { try { await updateIdentityWorkspaceRole.mutateAsync({ - workspaceId, + projectId, identityId: identityProjectMembership.identity.id, roles: sanitizedRoles }); diff --git a/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx b/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx index 7fadf2cb9..23b8299da 100644 --- a/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx +++ b/frontend/src/pages/project/MemberDetailsByIDPage/MemberDetailsByIDPage.tsx @@ -19,7 +19,7 @@ import { ProjectPermissionMemberActions, ProjectPermissionSub, useOrganization, - useWorkspace + useProject } from "@app/context"; import { getProjectBaseURL, getProjectHomePage } from "@app/helpers/project"; import { usePopUp } from "@app/hooks"; @@ -40,12 +40,10 @@ export const Page = () => { select: (el) => el.membershipId as string }); const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); - - const workspaceId = currentWorkspace?.id || ""; + const { currentProject, projectId } = useProject(); const { data: membershipDetails, isPending: isMembershipDetailsLoading } = - useGetWorkspaceUserDetails(workspaceId, membershipId); + useGetWorkspaceUserDetails(projectId, membershipId); const { mutateAsync: removeUserFromWorkspace, isPending: isRemovingUserFromWorkspace } = useDeleteUserFromWorkspace(); @@ -63,7 +61,7 @@ export const Page = () => { { actorId: userId, actorType: ActorType.USER, - projectId: workspaceId + projectId }, { onSuccess: () => { @@ -72,19 +70,19 @@ export const Page = () => { text: "User privilege assumption has started" }); - const url = getProjectHomePage(currentWorkspace.type, currentWorkspace.environments); - window.location.href = url.replace("$projectId", currentWorkspace.id); + const url = getProjectHomePage(currentProject.type, currentProject.environments); + window.location.href = url.replace("$projectId", currentProject.id); } } ); }; const handleRemoveUser = async () => { - if (!currentOrg?.id || !currentWorkspace?.id || !membershipDetails?.user?.username) return; + if (!currentOrg?.id || !currentProject?.id || !membershipDetails?.user?.username) return; try { await removeUserFromWorkspace({ - workspaceId: currentWorkspace.id, + projectId, usernames: [membershipDetails?.user?.username], orgId: currentOrg.id }); @@ -93,9 +91,9 @@ export const Page = () => { type: "success" }); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/access-management` as const, + to: `${getProjectBaseURL(currentProject.type)}/access-management` as const, params: { - projectId: currentWorkspace.id + projectId: currentProject.id } }); } catch (error) { diff --git a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx index 9817aefdb..6fa54247f 100644 --- a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx +++ b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberProjectAdditionalPrivilegeSection/MembershipProjectAdditionalPrivilegeModifySection.tsx @@ -23,8 +23,8 @@ import { import { ProjectPermissionMemberActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { useCreateProjectUserAdditionalPrivilege, @@ -77,8 +77,8 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({ isDisabled }: Props) => { const isCreate = !privilegeId; - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: privilegeDetails, isPending } = useGetProjectUserPrivilegeDetails( privilegeId || "" ); @@ -221,7 +221,7 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({ > Save - + diff --git a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleDetailsSection.tsx b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleDetailsSection.tsx index 5ff78360d..012141c03 100644 --- a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleDetailsSection.tsx +++ b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleDetailsSection.tsx @@ -22,12 +22,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { - ProjectPermissionActions, - ProjectPermissionSub, - useUser, - useWorkspace -} from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject, useUser } from "@app/context"; import { formatProjectRoleName } from "@app/helpers/roles"; import { usePopUp } from "@app/hooks"; import { useUpdateUserWorkspaceRole } from "@app/hooks/api"; @@ -49,7 +44,7 @@ export const MemberRoleDetailsSection = ({ }: Props) => { const { user } = useUser(); const userId = user?.id; - const { currentWorkspace } = useWorkspace(); + const { projectId } = useProject(); const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ "deleteRole", "modifyRole" @@ -63,7 +58,7 @@ export const MemberRoleDetailsSection = ({ try { const updatedRoles = membershipDetails?.roles?.filter((el) => el.id !== id); await updateUserWorkspaceRole({ - workspaceId: currentWorkspace?.id || "", + projectId, roles: updatedRoles.map( ({ role, diff --git a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleModify.tsx b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleModify.tsx index 739b22b7d..e7a05f70f 100644 --- a/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleModify.tsx +++ b/frontend/src/pages/project/MemberDetailsByIDPage/components/MemberRoleDetailsSection/MemberRoleModify.tsx @@ -29,14 +29,14 @@ import { ProjectPermissionActions, ProjectPermissionMemberActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { useGetProjectRoles, useUpdateUserWorkspaceRole } from "@app/hooks/api"; +import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; import { TWorkspaceUser } from "@app/hooks/api/types"; -import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types"; const roleFormSchema = z.object({ roles: z @@ -65,9 +65,8 @@ type Props = { export const MemberRoleModify = ({ projectMember, onOpenUpgradeModal }: Props) => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; - const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(workspaceId); + const { projectId } = useProject(); + const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles(projectId); const { permission } = useProjectPermission(); const isMemberEditDisabled = permission.cannot( ProjectPermissionMemberActions.Edit, @@ -131,7 +130,7 @@ export const MemberRoleModify = ({ projectMember, onOpenUpgradeModal }: Props) = try { await updateMembershipRole.mutateAsync({ - workspaceId, + projectId, membershipId: projectMember.id, roles: sanitizedRoles }); diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx index e400767a1..775244b4d 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/RoleDetailsBySlugPage.tsx @@ -16,7 +16,7 @@ import { DropdownMenuTrigger, PageHeader } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { useDeleteProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; @@ -33,8 +33,8 @@ const Page = () => { strict: false, select: (el) => el.roleSlug as string }); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data } = useGetProjectRoleBySlug(projectId, roleSlug as string); @@ -48,7 +48,7 @@ const Page = () => { const onDeleteRoleSubmit = async () => { try { - if (!currentWorkspace?.slug || !data?.id) return; + if (!currentProject?.slug || !data?.id) return; await deleteProjectRole({ projectId, @@ -61,7 +61,7 @@ const Page = () => { }); handlePopUpClose("deleteRole"); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/access-management` as const, + to: `${getProjectBaseURL(currentProject.type)}/access-management` as const, params: { projectId }, diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/AddPoliciesButton.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/AddPoliciesButton.tsx index abdf5c5d5..37f6b3868 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/AddPoliciesButton.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/AddPoliciesButton.tsx @@ -9,7 +9,7 @@ import { IconButton } from "@app/components/v2"; import { usePopUp } from "@app/hooks"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { PolicySelectionModal } from "@app/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal"; import { PolicyTemplateModal } from "@app/pages/project/RoleDetailsBySlugPage/components/PolicyTemplateModal"; diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/DuplicateProjectRoleModal.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/DuplicateProjectRoleModal.tsx index 24974225e..d36562089 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/DuplicateProjectRoleModal.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/DuplicateProjectRoleModal.tsx @@ -5,7 +5,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalContent, Spinner } from "@app/components/v2"; -import { ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject } from "@app/context"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { getProjectBaseURL } from "@app/helpers/project"; import { useCreateProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api"; @@ -45,7 +45,7 @@ const Content = ({ role, onClose }: ContentProps) => { resolver: zodResolver(schema) }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const createRole = useCreateProjectRole(); const navigate = useNavigate(); @@ -70,7 +70,7 @@ const Content = ({ role, onClose }: ContentProps) => { }); const newRole = await createRole.mutateAsync({ - projectId: currentWorkspace.id, + projectId: currentProject.id, permissions: sanitizedPermission, ...form }); @@ -81,10 +81,10 @@ const Content = ({ role, onClose }: ContentProps) => { }); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/roles/$roleSlug` as const, + to: `${getProjectBaseURL(currentProject.type)}/roles/$roleSlug` as const, params: { roleSlug: newRole.slug, - projectId: currentWorkspace.id + projectId: currentProject.id } }); @@ -142,9 +142,9 @@ const Content = ({ role, onClose }: ContentProps) => { }; export const DuplicateProjectRoleModal = ({ isOpen, onOpenChange, roleSlug }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const { data: role, isPending } = useGetProjectRoleBySlug(currentWorkspace.id, roleSlug ?? ""); + const { data: role, isPending } = useGetProjectRoleBySlug(currentProject.id, roleSlug ?? ""); if (!roleSlug) return null; diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx index 845c5f54e..22e64d48e 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicySelectionModal.tsx @@ -19,7 +19,7 @@ import { Tr } from "@app/components/v2"; import { ProjectPermissionSub } from "@app/context"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { EXCLUDED_PERMISSION_SUBS, diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicyTemplateModal.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicyTemplateModal.tsx index d9cae6244..3064311bc 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicyTemplateModal.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/PolicyTemplateModal.tsx @@ -13,7 +13,7 @@ import { ModalContent } from "@app/components/v2"; import { ProjectPermissionSub } from "@app/context"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { PROJECT_PERMISSION_OBJECT, diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx index f8032ac37..89c1e5d86 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx @@ -33,8 +33,8 @@ import { TPermissionCondition, TPermissionConditionOperators } from "@app/context/ProjectPermissionContext/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { TProjectPermission } from "@app/hooks/api/roles/types"; -import { ProjectType } from "@app/hooks/api/workspace/types"; const GeneralPolicyActionSchema = z.object({ read: z.boolean().optional(), diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RoleModal.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RoleModal.tsx index eb7a2ba83..e34f86892 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RoleModal.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RoleModal.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { getProjectBaseURL } from "@app/helpers/project"; import { useCreateProjectRole, @@ -38,8 +38,8 @@ export const RoleModal = ({ popUp, handlePopUpToggle }: Props) => { roleSlug: string; }; - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: role } = useGetProjectRoleBySlug(projectId, popupData?.roleSlug ?? ""); @@ -101,7 +101,7 @@ export const RoleModal = ({ popUp, handlePopUpToggle }: Props) => { }); navigate({ - to: `${getProjectBaseURL(currentWorkspace.type)}/roles/$roleSlug` as const, + to: `${getProjectBaseURL(currentProject.type)}/roles/$roleSlug` as const, params: { roleSlug: newRole.slug, projectId diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx index f11756dc9..347ebaf99 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection.tsx @@ -8,12 +8,12 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { createNotification } from "@app/components/notifications"; import { AccessTree } from "@app/components/permissions"; import { Button } from "@app/components/v2"; -import { ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject } from "@app/context"; import { ProjectPermissionSet } from "@app/context/ProjectPermissionContext"; import { evaluatePermissionsAbility } from "@app/helpers/permissions"; import { useGetProjectRoleBySlug, useUpdateProjectRole } from "@app/hooks/api"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { ProjectType } from "@app/hooks/api/workspace/types"; import { AddPoliciesButton } from "./AddPoliciesButton"; import { AppConnectionPermissionConditions } from "./AppConnectionPermissionConditions"; @@ -89,10 +89,10 @@ export const renderConditionalComponents = ( }; export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: role, isPending } = useGetProjectRoleBySlug( - currentWorkspace?.id ?? "", + currentProject?.id ?? "", roleSlug as string ); @@ -131,7 +131,7 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { (role?.slug ?? "") as ProjectMembershipRole ); - const isSecretManagerProject = currentWorkspace.type === ProjectType.SecretManager; + const isSecretManagerProject = currentProject.type === ProjectType.SecretManager; const permissions = form.watch("permissions"); @@ -183,7 +183,7 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => { Save
- +
)} diff --git a/frontend/src/pages/project/SettingsPage/components/AuditLogsRetentionSection/AuditLogsRetentionSection.tsx b/frontend/src/pages/project/SettingsPage/components/AuditLogsRetentionSection/AuditLogsRetentionSection.tsx index 7c65b1857..11f4f0270 100644 --- a/frontend/src/pages/project/SettingsPage/components/AuditLogsRetentionSection/AuditLogsRetentionSection.tsx +++ b/frontend/src/pages/project/SettingsPage/components/AuditLogsRetentionSection/AuditLogsRetentionSection.tsx @@ -5,10 +5,10 @@ import { z } from "zod"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input } from "@app/components/v2"; -import { useProjectPermission, useSubscription, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission, useSubscription } from "@app/context"; import { usePopUp } from "@app/hooks"; +import { useUpdateWorkspaceAuditLogsRetention } from "@app/hooks/api/projects/queries"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { useUpdateWorkspaceAuditLogsRetention } from "@app/hooks/api/workspace/queries"; const formSchema = z.object({ auditLogsRetentionDays: z.coerce.number().min(0) @@ -19,7 +19,7 @@ type TForm = z.infer; export const AuditLogsRetentionSection = () => { const { mutateAsync: updateAuditLogsRetention } = useUpdateWorkspaceAuditLogsRetention(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { membership } = useProjectPermission(); const { subscription } = useSubscription(); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const); @@ -32,11 +32,11 @@ export const AuditLogsRetentionSection = () => { resolver: zodResolver(formSchema), values: { auditLogsRetentionDays: - currentWorkspace?.auditLogsRetentionDays ?? subscription?.auditLogsRetentionDays ?? 0 + currentProject?.auditLogsRetentionDays ?? subscription?.auditLogsRetentionDays ?? 0 } }); - if (!currentWorkspace) return null; + if (!currentProject) return null; const handleAuditLogsRetentionSubmit = async ({ auditLogsRetentionDays }: TForm) => { try { @@ -59,7 +59,7 @@ export const AuditLogsRetentionSection = () => { await updateAuditLogsRetention({ auditLogsRetentionDays, - projectSlug: currentWorkspace.slug + projectSlug: currentProject.slug }); createNotification({ diff --git a/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx b/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx index 2ac123607..efc69831d 100644 --- a/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx +++ b/frontend/src/pages/project/SettingsPage/components/DeleteProjectProtection/DeleteProjectProtection.tsx @@ -1,20 +1,19 @@ import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Checkbox } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; -import { useToggleDeleteProjectProtection } from "@app/hooks/api/workspace/queries"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; +import { useUpdateProject } from "@app/hooks/api"; export const DeleteProjectProtection = () => { - const { currentWorkspace } = useWorkspace(); - const { mutateAsync } = useToggleDeleteProjectProtection(); + const { projectId, currentProject } = useProject(); + + const { mutateAsync } = useUpdateProject(); const handleToggleDeleteProjectProtection = async (state: boolean) => { try { - if (!currentWorkspace?.id) return; - await mutateAsync({ - workspaceID: currentWorkspace.id, - state + projectId, + hasDeleteProtection: state }); const text = `Successfully ${state ? "enabled" : "disabled"} delete protection`; @@ -40,7 +39,7 @@ export const DeleteProjectProtection = () => { { handleToggleDeleteProjectProtection(state as boolean); }} diff --git a/frontend/src/pages/project/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx b/frontend/src/pages/project/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx index ac589ba59..4771e0c88 100644 --- a/frontend/src/pages/project/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx +++ b/frontend/src/pages/project/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx @@ -9,8 +9,8 @@ import { ProjectPermissionActions, ProjectPermissionSub, useOrganization, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { useToggle } from "@app/hooks"; import { useDeleteWorkspace, useGetWorkspaceUsers, useLeaveProject } from "@app/hooks/api"; @@ -26,13 +26,13 @@ export const DeleteProjectSection = () => { const { currentOrg } = useOrganization(); const { hasProjectRole, membership } = useProjectPermission(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [isDeleting, setIsDeleting] = useToggle(); const [isLeaving, setIsLeaving] = useToggle(); const deleteWorkspace = useDeleteWorkspace(); const leaveProject = useLeaveProject(); const { data: members, isPending: isMembersLoading } = useGetWorkspaceUsers( - currentWorkspace?.id || "" + currentProject?.id || "" ); // If isNoAccessMember is true, then the user can't read the workspace members. So we need to handle this case separately. @@ -51,10 +51,10 @@ export const DeleteProjectSection = () => { const handleDeleteWorkspaceSubmit = async () => { setIsDeleting.on(); try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await deleteWorkspace.mutateAsync({ - workspaceID: currentWorkspace?.id + projectID: currentProject?.id }); createNotification({ @@ -81,7 +81,7 @@ export const DeleteProjectSection = () => { try { setIsLeaving.on(); - if (!currentWorkspace?.id || !currentOrg?.id) return; + if (!currentProject?.id || !currentOrg?.id) return; // If there's no members, and the user has access to read members, something went wrong. if (!members && !isNoAccessMember) return; @@ -110,7 +110,7 @@ export const DeleteProjectSection = () => { // If it's actually a no-access member, then we don't really care about the members. await leaveProject.mutateAsync({ - workspaceId: currentWorkspace.id + projectId: currentProject.id }); navigate({ @@ -141,7 +141,7 @@ export const DeleteProjectSection = () => { type="submit" onClick={() => handlePopUpOpen("deleteWorkspace")} > - {`Delete ${currentWorkspace?.name}`} + {`Delete ${currentProject?.name}`} )} @@ -154,7 +154,7 @@ export const DeleteProjectSection = () => { type="submit" onClick={() => handlePopUpOpen("leaveWorkspace")} > - {`Leave ${currentWorkspace?.name}`} + {`Leave ${currentProject?.name}`} )} @@ -162,7 +162,7 @@ export const DeleteProjectSection = () => { handlePopUpToggle("deleteWorkspace", isOpen)} deleteKey="confirm" buttonText="Delete Project" @@ -172,7 +172,7 @@ export const DeleteProjectSection = () => { handlePopUpToggle("leaveWorkspace", isOpen)} deleteKey="confirm" buttonText="Leave Project" diff --git a/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx b/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx index 06f79e9f0..facbd782b 100644 --- a/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx +++ b/frontend/src/pages/secret-manager/CommitDetailsPage/CommitDetailsPage.tsx @@ -2,7 +2,7 @@ import { useNavigate, useParams, useSearch } from "@tanstack/react-router"; import { ProjectPermissionCan } from "@app/components/permissions"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { ProjectPermissionCommitsActions, ProjectPermissionSub @@ -23,7 +23,7 @@ export const CommitDetailsPage = () => { from: ROUTE_PATHS.SecretManager.CommitDetailsPage.id, select: (el) => el.folderId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const routerQueryParams: { secretPath?: string } = useSearch({ @@ -36,7 +36,7 @@ export const CommitDetailsPage = () => { navigate({ to: "/projects/secret-management/$projectId/commits/$environment/$folderId", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, folderId, environment: envSlug }, @@ -51,7 +51,7 @@ export const CommitDetailsPage = () => { navigate({ to: "/projects/secret-management/$projectId/commits/$environment/$folderId/$commitId/restore", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, folderId, environment: envSlug, commitId: selectedCommitId @@ -73,7 +73,7 @@ export const CommitDetailsPage = () => { > { export const CommitDetailsTab = ({ selectedCommitId, - workspaceId, + projectId, envSlug, goBackToHistory, goToRollbackPreview }: { selectedCommitId: string; - workspaceId: string; + projectId: string; envSlug: string; goBackToHistory: () => void; goToRollbackPreview: () => void; @@ -71,7 +71,7 @@ export const CommitDetailsTab = ({ "revertChanges" ] as const); - const { data: commitDetails, isLoading } = useGetCommitDetails(workspaceId, selectedCommitId); + const { data: commitDetails, isLoading } = useGetCommitDetails(projectId, selectedCommitId); const routerQueryParams: { secretPath?: string } = useSearch({ from: ROUTE_PATHS.SecretManager.CommitDetailsPage.id @@ -80,7 +80,7 @@ export const CommitDetailsTab = ({ const { mutateAsync: revert } = useCommitRevert({ commitId: selectedCommitId, - projectId: workspaceId, + projectId, environment: envSlug, directory: secretPath }); diff --git a/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx b/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx index e06daea38..ae082d8ea 100644 --- a/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx +++ b/frontend/src/pages/secret-manager/CommitDetailsPage/components/RollbackPreviewTab/RollbackPreviewTab.tsx @@ -17,7 +17,7 @@ import { Tooltip } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { ProjectPermissionCommitsActions, ProjectPermissionSub @@ -79,7 +79,7 @@ export const RollbackPreviewTab = (): JSX.Element => { const [deepRollback, setDeepRollback] = useState(false); const [message, setMessage] = useState(""); const [selectedFolderId, setSelectedFolderId] = useState(null); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const envSlug = useParams({ from: ROUTE_PATHS.SecretManager.RollbackPreviewPage.id, select: (el) => el.environment @@ -104,7 +104,7 @@ export const RollbackPreviewTab = (): JSX.Element => { navigate({ to: "/projects/secret-management/$projectId/commits/$environment/$folderId", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, folderId, environment: envSlug }, @@ -120,7 +120,7 @@ export const RollbackPreviewTab = (): JSX.Element => { ] as const); const { mutateAsync: rollback } = useCommitRollback({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, commitId: selectedCommitId, folderId, deepRollback, @@ -133,7 +133,7 @@ export const RollbackPreviewTab = (): JSX.Element => { folderId, selectedCommitId, envSlug, - currentWorkspace.id, + currentProject.id, deepRollback, secretPath ); diff --git a/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx b/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx index 1acb76446..2dba8ad55 100644 --- a/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx +++ b/frontend/src/pages/secret-manager/CommitsPage/CommitsPage.tsx @@ -4,7 +4,7 @@ import { ProjectPermissionCan } from "@app/components/permissions"; import { PageHeader } from "@app/components/v2"; import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { ProjectPermissionCommitsActions, ProjectPermissionSub @@ -17,7 +17,7 @@ export const CommitsPage = () => { from: ROUTE_PATHS.SecretManager.CommitsPage.id, select: (el) => el.environment }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const folderId = useParams({ from: ROUTE_PATHS.SecretManager.CommitsPage.id, @@ -33,7 +33,7 @@ export const CommitsPage = () => { navigate({ to: "/projects/secret-management/$projectId/commits/$environment/$folderId/$commitId", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, folderId, environment: envSlug, commitId @@ -67,7 +67,7 @@ export const CommitsPage = () => { > diff --git a/frontend/src/pages/secret-manager/CommitsPage/components/CommitHistoryTab/CommitHistoryTab.tsx b/frontend/src/pages/secret-manager/CommitsPage/components/CommitHistoryTab/CommitHistoryTab.tsx index 58191f389..d5f982529 100644 --- a/frontend/src/pages/secret-manager/CommitsPage/components/CommitHistoryTab/CommitHistoryTab.tsx +++ b/frontend/src/pages/secret-manager/CommitsPage/components/CommitHistoryTab/CommitHistoryTab.tsx @@ -136,7 +136,7 @@ export const CommitHistoryTab = ({ isFetchingNextPage, hasNextPage } = useGetFolderCommitHistory({ - workspaceId: projectId, + projectId, environment, directory: secretPath, limit, diff --git a/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistModal.tsx b/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistModal.tsx index 4d95b6388..36f585850 100644 --- a/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistModal.tsx +++ b/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistModal.tsx @@ -5,7 +5,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useAddTrustedIp, useGetMyIp, useUpdateTrustedIp } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -27,7 +27,7 @@ type Props = { export const IPAllowlistModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => { const { data, isPending } = useGetMyIp(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const addTrustedIp = useAddTrustedIp(); const updateTrustedIp = useUpdateTrustedIp(); @@ -65,11 +65,11 @@ export const IPAllowlistModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: const onIPAllowlistModalSubmit = async ({ ipAddress, comment }: FormData) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; if (popUp?.trustedIp?.data) { await updateTrustedIp.mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, trustedIpId: (popUp?.trustedIp?.data as { trustedIpId: string })?.trustedIpId, ipAddress, comment, @@ -77,7 +77,7 @@ export const IPAllowlistModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: }); } else { await addTrustedIp.mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, ipAddress, comment, isActive: true diff --git a/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistSection.tsx b/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistSection.tsx index 63b410ee2..fc2890b7f 100644 --- a/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistSection.tsx +++ b/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistSection.tsx @@ -8,8 +8,8 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, - useSubscription, - useWorkspace + useProject, + useSubscription } from "@app/context"; import { useDeleteTrustedIp } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -20,7 +20,7 @@ import { IPAllowlistTable } from "./IPAllowlistTable"; export const IPAllowlistSection = () => { const { mutateAsync } = useDeleteTrustedIp(); const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ "trustedIp", @@ -30,10 +30,10 @@ export const IPAllowlistSection = () => { const onDeleteTrustedIpSubmit = async (trustedIpId: string) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, trustedIpId }); diff --git a/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistTable.tsx b/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistTable.tsx index 42ecc8d8a..8f3336be8 100644 --- a/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistTable.tsx +++ b/frontend/src/pages/secret-manager/IPAllowlistPage/components/IPAllowlistTable.tsx @@ -18,8 +18,8 @@ import { import { ProjectPermissionActions, ProjectPermissionSub, - useSubscription, - useWorkspace + useProject, + useSubscription } from "@app/context"; import { useGetTrustedIps } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -41,8 +41,8 @@ type Props = { export const IPAllowlistTable = ({ popUp, handlePopUpOpen, handlePopUpToggle }: Props) => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useGetTrustedIps(currentWorkspace?.id ?? ""); + const { currentProject } = useProject(); + const { data, isPending } = useGetTrustedIps(currentProject?.id ?? ""); const formatType = (type: string, prefix?: number) => { return `${type.slice(0, 2).toUpperCase() + type.slice(2)} ${ @@ -77,10 +77,10 @@ export const IPAllowlistTable = ({ popUp, handlePopUpOpen, handlePopUpToggle }: {comment} {/*
- + />

Active

*/} diff --git a/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx b/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx index c1ba83ae6..3788d955e 100644 --- a/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/IntegrationsDetailsByIDPage.tsx @@ -20,11 +20,11 @@ import { Tooltip } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { OrgPermissionActions, OrgPermissionSubjects, useWorkspace } from "@app/context"; +import { OrgPermissionActions, OrgPermissionSubjects, useProject } from "@app/context"; import { usePopUp, useToggle } from "@app/hooks"; import { useGetIntegration } from "@app/hooks/api"; import { useDeleteIntegration, useSyncIntegration } from "@app/hooks/api/integrations/queries"; -import { ProjectType } from "@app/hooks/api/workspace/types"; +import { ProjectType } from "@app/hooks/api/projects/types"; import { IntegrationAuditLogsSection } from "./components/IntegrationAuditLogsSection"; import { IntegrationConnectionSection } from "./components/IntegrationConnectionSection"; @@ -45,8 +45,8 @@ export const IntegrationDetailsByIDPage = () => { const [shouldDeleteSecrets, setShouldDeleteSecrets] = useToggle(false); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const { mutateAsync: syncIntegration } = useSyncIntegration(); const { mutateAsync: deleteIntegration } = useDeleteIntegration(); @@ -56,7 +56,7 @@ export const IntegrationDetailsByIDPage = () => { try { await deleteIntegration({ id: integrationId, - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, shouldDeleteIntegrationSecrets }); diff --git a/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/components/IntegrationAuditLogsSection.tsx b/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/components/IntegrationAuditLogsSection.tsx index c27b1bb08..6a808814e 100644 --- a/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/components/IntegrationAuditLogsSection.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsDetailsByIDPage/components/IntegrationAuditLogsSection.tsx @@ -1,7 +1,7 @@ import { Link } from "@tanstack/react-router"; import { EmptyState } from "@app/components/v2"; -import { useSubscription, useWorkspace } from "@app/context"; +import { useProject, useSubscription } from "@app/context"; import { EventType } from "@app/hooks/api/auditLogs/enums"; import { TIntegrationWithEnv } from "@app/hooks/api/integrations/types"; import { LogsSection } from "@app/pages/organization/AuditLogsPage/components/LogsSection"; @@ -15,7 +15,7 @@ type Props = { export const IntegrationAuditLogsSection = ({ integration }: Props) => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const auditLogsRetentionDays = subscription?.auditLogsRetentionDays ?? 30; @@ -31,7 +31,7 @@ export const IntegrationAuditLogsSection = ({ integration }: Props) => { { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { t } = useTranslation(); const { selectedTab } = useSearch({ @@ -30,7 +30,7 @@ export const IntegrationsListPage = () => { to: ROUTE_PATHS.SecretManager.IntegrationsListPage.path, search: (prev) => ({ ...prev, selectedTab: tab as IntegrationsListPageTabs }), params: { - projectId: currentWorkspace.id + projectId: currentProject.id } }); }; diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/CloudIntegrationSection/CloudIntegrationSection.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/CloudIntegrationSection/CloudIntegrationSection.tsx index 935ad1a8c..42f661606 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/CloudIntegrationSection/CloudIntegrationSection.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/CloudIntegrationSection/CloudIntegrationSection.tsx @@ -24,8 +24,8 @@ import { ROUTE_PATHS } from "@app/const/routes"; import { ProjectPermissionActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { usePopUp } from "@app/hooks"; import { SecretSync } from "@app/hooks/api/secretSyncs"; @@ -60,7 +60,7 @@ export const CloudIntegrationSection = ({ "deleteConfirmation" ] as const); const { permission } = useProjectPermission(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const isEmpty = !isLoading && !cloudIntegrations?.length; @@ -68,12 +68,12 @@ export const CloudIntegrationSection = ({ const sortedCloudIntegrations = useMemo(() => { const sortedIntegrations = cloudIntegrations.sort((a, b) => a.name.localeCompare(b.name)); - if (currentWorkspace?.environments.length === 0) { + if (currentProject?.environments.length === 0) { return sortedIntegrations.map((integration) => ({ ...integration, isAvailable: false })); } return sortedIntegrations; - }, [cloudIntegrations, currentWorkspace?.environments]); + }, [cloudIntegrations, currentProject?.environments]); const [search, setSearch] = useState(""); @@ -83,9 +83,9 @@ export const CloudIntegrationSection = ({ return (
- {currentWorkspace?.environments.length === 0 && ( + {currentProject?.environments.length === 0 && (
- +
)}
@@ -138,7 +138,7 @@ export const CloudIntegrationSection = ({ navigate({ to: ROUTE_PATHS.SecretManager.IntegrationsListPage.path, params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.SecretSyncs, diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationRow.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationRow.tsx index df862b8ba..c83e24254 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationRow.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/IntegrationRow.tsx @@ -15,7 +15,7 @@ import { twMerge } from "tailwind-merge"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Badge, IconButton, Td, Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { TCloudIntegration } from "@app/hooks/api/integrations/types"; import { TIntegration } from "@app/hooks/api/types"; @@ -37,7 +37,7 @@ export const IntegrationRow = ({ cloudIntegration }: IProps) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { id, secretPath, syncMessage, isSynced } = integration; @@ -62,7 +62,7 @@ export const IntegrationRow = ({ to: "/projects/secret-management/$projectId/integrations/$integrationId", params: { integrationId: integration.id, - projectId: currentWorkspace.id + projectId: currentProject.id } }) } diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/NativeIntegrationsTab.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/NativeIntegrationsTab.tsx index f3706940c..b4f790075 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/NativeIntegrationsTab.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/NativeIntegrationsTab/NativeIntegrationsTab.tsx @@ -5,7 +5,7 @@ import { useNavigate } from "@tanstack/react-router"; import { createNotification } from "@app/components/notifications"; import { Button, Checkbox, DeleteActionModal, Spinner } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { usePopUp, useToggle } from "@app/hooks"; import { useDeleteIntegration, @@ -27,8 +27,8 @@ enum IntegrationView { } export const NativeIntegrationsTab = () => { - const { currentWorkspace } = useWorkspace(); - const { environments, id: workspaceId } = currentWorkspace; + const { currentProject } = useProject(); + const { environments, id: workspaceId } = currentProject; const navigate = useNavigate(); const { data: cloudIntegrations, isPending: isCloudIntegrationsLoading } = @@ -91,7 +91,7 @@ export const NativeIntegrationsTab = () => { if (!selectedCloudIntegration) return; try { - redirectForProviderAuth(currentWorkspace.id, navigate, selectedCloudIntegration); + redirectForProviderAuth(currentProject.id, navigate, selectedCloudIntegration); } catch (error) { console.error(error); } diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx index fcd42a10f..ed96dcd45 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncsTable.tsx @@ -36,7 +36,7 @@ import { THead, Tr } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs"; import { getUserTablePreference, @@ -109,7 +109,7 @@ export const SecretSyncsTable = ({ secretSyncs }: Props) => { environmentIds: [] }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { search, @@ -372,7 +372,7 @@ export const SecretSyncsTable = ({ secretSyncs }: Props) => { No Secret Syncs Configured )} Environment - {currentWorkspace.environments.map((env) => ( + {currentProject.environments.map((env) => ( { e.preventDefault(); diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncsTab.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncsTab.tsx index 036fcf03f..f1866cda0 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncsTab.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncsTab.tsx @@ -8,7 +8,7 @@ import { CreateSecretSyncModal } from "@app/components/secret-syncs"; import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas"; import { Button, Spinner } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject } from "@app/context"; import { ProjectPermissionSecretSyncActions } from "@app/context/ProjectPermissionContext/types"; import { usePopUp } from "@app/hooks"; import { useListSecretSyncs } from "@app/hooks/api/secretSyncs"; @@ -25,7 +25,7 @@ export const SecretSyncsTab = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { if (!addSync) return; @@ -34,7 +34,7 @@ export const SecretSyncsTab = () => { navigate({ to: ROUTE_PATHS.SecretManager.IntegrationsListPage.path, params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search }); @@ -65,7 +65,7 @@ export const SecretSyncsTab = () => { navigate({ to: ROUTE_PATHS.SecretManager.IntegrationsListPage.path, params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search }); @@ -73,7 +73,7 @@ export const SecretSyncsTab = () => { }, [connectionId, connectionName]); const { data: secretSyncs = [], isPending: isSecretSyncsPending } = useListSecretSyncs( - currentWorkspace.id, + currentProject.id, { refetchInterval: 30000 } diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/route.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/route.tsx index fa25fbe20..405aec3e9 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/route.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/route.tsx @@ -2,15 +2,15 @@ import { createFileRoute, redirect } from "@tanstack/react-router"; import { zodValidator } from "@tanstack/zod-adapter"; import { z } from "zod"; -import { workspaceKeys } from "@app/hooks/api"; +import { projectKeys } from "@app/hooks/api"; import { TIntegration } from "@app/hooks/api/integrations/types"; +import { fetchWorkspaceIntegrations } from "@app/hooks/api/projects/queries"; import { fetchSecretSyncsByProjectId, SecretSync, secretSyncKeys, TSecretSync } from "@app/hooks/api/secretSyncs"; -import { fetchWorkspaceIntegrations } from "@app/hooks/api/workspace/queries"; import { IntegrationsListPageTabs } from "@app/types/integrations"; import { IntegrationsListPage } from "./IntegrationsListPage"; @@ -59,7 +59,7 @@ export const Route = createFileRoute( let integrations: TIntegration[]; try { integrations = await context.queryClient.ensureQueryData({ - queryKey: workspaceKeys.getWorkspaceIntegrations(projectId), + queryKey: projectKeys.getProjectIntegrations(projectId), queryFn: () => fetchWorkspaceIntegrations(projectId) }); } catch { diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx index 910e07eac..ab9b332b0 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx @@ -63,9 +63,9 @@ import { ProjectPermissionActions, ProjectPermissionDynamicSecretActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { ProjectPermissionSecretRotationActions } from "@app/context/ProjectPermissionContext/types"; import { @@ -92,16 +92,11 @@ import { import { useGetProjectSecretsOverview } from "@app/hooks/api/dashboard/queries"; import { DashboardSecretsOrderBy, ProjectSecretsImportedBy } from "@app/hooks/api/dashboard/types"; import { OrderByDirection } from "@app/hooks/api/generic/types"; +import { ProjectVersion } from "@app/hooks/api/projects/types"; import { useUpdateFolderBatch } from "@app/hooks/api/secretFolders/queries"; import { TUpdateFolderBatchDTO } from "@app/hooks/api/secretFolders/types"; import { TSecretRotationV2 } from "@app/hooks/api/secretRotationsV2"; -import { - SecretType, - SecretV3RawSanitized, - TSecretFolder, - WorkspaceEnv -} from "@app/hooks/api/types"; -import { ProjectVersion } from "@app/hooks/api/workspace/types"; +import { ProjectEnv, SecretType, SecretV3RawSanitized, TSecretFolder } from "@app/hooks/api/types"; import { useDynamicSecretOverview, useFolderOverview, @@ -173,10 +168,9 @@ export const OverviewPage = () => { const [debouncedScrollOffset] = useDebounce(scrollOffset); const { permission } = useProjectPermission(); const tableRef = useRef(null); - const { currentWorkspace } = useWorkspace(); - const isProjectV3 = currentWorkspace?.version === ProjectVersion.V3; - const workspaceId = currentWorkspace?.id as string; - const projectSlug = currentWorkspace?.slug as string; + const { currentProject, projectId } = useProject(); + const isProjectV3 = currentProject?.version === ProjectVersion.V3; + const projectSlug = currentProject?.slug as string; const [searchFilter, setSearchFilter] = useState(""); const [debouncedSearchFilter, setDebouncedSearchFilter] = useDebounce(searchFilter); const secretPath = (routerSearch?.secretPath as string) || "/"; @@ -246,7 +240,7 @@ export const OverviewPage = () => { }; }, []); - const userAvailableEnvs = currentWorkspace?.environments || []; + const userAvailableEnvs = currentProject?.environments || []; const userAvailableDynamicSecretEnvs = userAvailableEnvs.filter((env) => permission.can( ProjectPermissionDynamicSecretActions.CreateRootCredential, @@ -267,7 +261,7 @@ export const OverviewPage = () => { ) ); - const [filteredEnvs, setFilteredEnvs] = useState([]); + const [filteredEnvs, setFilteredEnvs] = useState([]); const visibleEnvs = filteredEnvs.length ? filteredEnvs : userAvailableEnvs; const { @@ -276,7 +270,7 @@ export const OverviewPage = () => { getImportedSecretByKey, getEnvImportedSecretKeyCount } = useGetImportedSecretsAllEnvs({ - projectId: workspaceId, + projectId, path: secretPath, environments: (userAvailableEnvs || []).map(({ slug }) => slug) }); @@ -284,7 +278,7 @@ export const OverviewPage = () => { const isFilteredByResources = Object.values(filter).some(Boolean); const { isPending: isOverviewLoading, data: overview } = useGetProjectSecretsOverview( { - projectId: workspaceId, + projectId, environments: visibleEnvs.map((env) => env.slug), secretPath, orderDirection, @@ -368,7 +362,7 @@ export const OverviewPage = () => { ); const { data: tags } = useGetWsTags( - permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags) ? workspaceId : "" + permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags) ? projectId : "" ); const { mutateAsync: createSecretV3 } = useCreateSecretV3(); @@ -398,7 +392,7 @@ export const OverviewPage = () => { name: folderName, path: secretPath, environment, - projectId: workspaceId, + projectId, description }); }); @@ -456,9 +450,8 @@ export const OverviewPage = () => { try { await updateFolderBatch({ - projectSlug, folders: updatedFolders, - projectId: workspaceId + projectId }); createNotification({ type: "success", @@ -491,7 +484,7 @@ export const OverviewPage = () => { ); if (folderName && parentPath && canCreateFolder) { await createFolder({ - projectId: workspaceId, + projectId, path: parentPath, environment: env, name: folderName @@ -500,7 +493,7 @@ export const OverviewPage = () => { } const result = await createSecretV3({ environment: env, - workspaceId, + projectId, secretPath, secretKey: key, secretValue: value, @@ -555,7 +548,7 @@ export const OverviewPage = () => { try { const result = await updateSecretV3({ environment: env, - workspaceId, + projectId, secretPath, secretKey: key, secretValue, @@ -586,7 +579,7 @@ export const OverviewPage = () => { try { const result = await deleteSecretV3({ environment: env, - workspaceId, + projectId, secretPath, secretKey: key, secretId, @@ -655,7 +648,7 @@ export const OverviewPage = () => { ); if (folderName && parentPath && canCreateFolder) { await createFolder({ - projectId: workspaceId, + projectId, environment: slug, path: parentPath, name: folderName @@ -669,7 +662,7 @@ export const OverviewPage = () => { navigate({ to: "/projects/secret-management/$projectId/secrets/$envSlug", params: { - projectId: workspaceId, + projectId, envSlug: slug }, search: query @@ -1099,7 +1092,7 @@ export const OverviewPage = () => { tags={tags} onChange={setSearchFilter} environments={userAvailableEnvs} - projectId={currentWorkspace?.id} + projectId={currentProject?.id} /> {userAvailableEnvs.length > 0 && (
@@ -1419,7 +1412,7 @@ export const OverviewPage = () => { diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx index 7087faf72..d4f8bbafe 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/CreateSecretForm/CreateSecretForm.tsx @@ -19,8 +19,8 @@ import { InfisicalSecretInput } from "@app/components/v2/InfisicalSecretInput"; import { ProjectPermissionActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { getKeyValue } from "@app/helpers/parseEnvVar"; @@ -57,16 +57,15 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { formState: { isSubmitting, errors } } = useForm({ resolver: zodResolver(typeSchema) }); - const { currentWorkspace } = useWorkspace(); + const { currentProject, projectId } = useProject(); const { permission } = useProjectPermission(); const canReadTags = permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags); - const workspaceId = currentWorkspace?.id || ""; - const environments = currentWorkspace?.environments || []; + const environments = currentProject?.environments || []; const { mutateAsync: createSecretV3 } = useCreateSecretV3(); const { mutateAsync: createFolder } = useCreateFolder(); const { data: projectTags, isPending: isTagsLoading } = useGetWsTags( - canReadTags ? workspaceId : "" + canReadTags ? projectId : "" ); const secretKeyInputRef = useRef(null); @@ -93,7 +92,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { if (folderName && parentPath && canCreateFolder) { await createFolder({ - projectId: workspaceId, + projectId, path: parentPath, environment, name: folderName @@ -106,7 +105,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { return { ...(await createSecretV3({ environment, - workspaceId, + projectId, secretPath, secretKey: key, secretValue: value || "", @@ -176,7 +175,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { if (!secretKey || isWholeKeyHighlighted) { e.preventDefault(); - const keyStr = currentWorkspace.autoCapitalization ? key.toUpperCase() : key; + const keyStr = currentProject.autoCapitalization ? key.toUpperCase() : key; setValue("key", keyStr); if (value) { setValue("value", value); @@ -191,7 +190,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { try { const parsedSlug = slugSchema.parse(slug); await createWsTag.mutateAsync({ - workspaceID: workspaceId, + projectId, tagSlug: parsedSlug, tagColor: "" }); @@ -220,7 +219,7 @@ export const CreateSecretForm = ({ secretPath = "/", onClose }: Props) => { }} placeholder="Type your secret name" onPaste={handlePaste} - autoCapitalization={currentWorkspace?.autoCapitalization} + autoCapitalization={currentProject?.autoCapitalization} /> { secret?: SecretV3RawSanitized; environmentInfo?: WorkspaceEnv } | undefined; + ) => { secret?: SecretV3RawSanitized; environmentInfo?: ProjectEnv } | undefined; scrollOffset: number; importedBy?: { environment: { name: string; slug: string }; diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx index d15e96a91..5e1f27f57 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretOverviewTableRow/SecretRenameRow.tsx @@ -10,7 +10,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { IconButton, Input, Spinner, Tooltip } from "@app/components/v2"; -import { ProjectPermissionSub, useProjectPermission, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject, useProjectPermission } from "@app/context"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { useToggle } from "@app/hooks"; import { useUpdateSecretV3 } from "@app/hooks/api"; @@ -37,7 +37,7 @@ export const formSchema = z.object({ type TFormSchema = z.infer; function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath }: Props) { - const { currentWorkspace } = useWorkspace(); + const { currentProject, projectId } = useProject(); const { permission } = useProjectPermission(); const secrets = environments.map((env) => getSecretByKey(env.slug, secretKey)); @@ -68,7 +68,6 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath } secret?.overrideAction === SecretActionType.Created || secret?.overrideAction === SecretActionType.Modified ); - const workspaceId = currentWorkspace?.id || ""; const [isSecNameCopied, setIsSecNameCopied] = useToggle(false); @@ -111,7 +110,7 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath } return updateSecretV3({ environment: secret?.env, - workspaceId, + projectId, secretPath, secretKey: secret.key, secretValue: secret.value || "", @@ -163,7 +162,7 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath } void; isSingleEnv?: boolean; diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SecretV2MigrationSection/SecretV2MigrationSection.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SecretV2MigrationSection/SecretV2MigrationSection.tsx index 14faa7e9e..048589827 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SecretV2MigrationSection/SecretV2MigrationSection.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SecretV2MigrationSection/SecretV2MigrationSection.tsx @@ -8,11 +8,11 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, Checkbox, Modal, ModalContent, Spinner } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { usePopUp } from "@app/hooks"; -import { useGetWorkspaceById, useMigrateProjectToV3, workspaceKeys } from "@app/hooks/api"; +import { projectKeys, useGetWorkspaceById, useMigrateProjectToV3 } from "@app/hooks/api"; +import { ProjectVersion } from "@app/hooks/api/projects/types"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { ProjectVersion } from "@app/hooks/api/workspace/types"; enum ProjectUpgradeStatus { InProgress = "IN_PROGRESS", @@ -28,14 +28,14 @@ const formSchema = z.object({ export const SecretV2MigrationSection = () => { const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["migrationInfo"] as const); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const queryClient = useQueryClient(); const { data: workspaceDetails, refetch } = useGetWorkspaceById( // if v3 no need to fetch - currentWorkspace?.version === ProjectVersion.V3 ? "" : currentWorkspace?.id || "", + currentProject?.version === ProjectVersion.V3 ? "" : currentProject?.id || "", { refetchInterval: - currentWorkspace?.upgradeStatus === ProjectUpgradeStatus.InProgress ? 2000 : false + currentProject?.upgradeStatus === ProjectUpgradeStatus.InProgress ? 2000 : false } ); const { membership } = useProjectPermission(); @@ -54,12 +54,12 @@ export const SecretV2MigrationSection = () => { createNotification({ type: "success", text: "Project upgrade completed successfully" }); migrateProjectToV3.reset(); queryClient.invalidateQueries({ - queryKey: workspaceKeys.getAllUserWorkspace() + queryKey: projectKeys.getAllUserProjects() }); } }, [isProjectUpgraded, Boolean(migrateProjectToV3.data)]); - if (isProjectUpgraded || currentWorkspace?.version === ProjectVersion.V3) return null; + if (isProjectUpgraded || currentProject?.version === ProjectVersion.V3) return null; const isUpgrading = workspaceDetails?.upgradeStatus === ProjectUpgradeStatus.InProgress; const didProjectUpgradeFailed = workspaceDetails?.upgradeStatus === ProjectUpgradeStatus.Failed; @@ -67,7 +67,7 @@ export const SecretV2MigrationSection = () => { const handleMigrationSecretV2 = async () => { try { handlePopUpToggle("migrationInfo"); - await migrateProjectToV3.mutateAsync({ workspaceId: currentWorkspace?.id || "" }); + await migrateProjectToV3.mutateAsync({ projectId: currentProject?.id || "" }); refetch(); createNotification({ text: "Project upgrade started", diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/SelectionPanel.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/SelectionPanel.tsx index 11ee3def8..8f84cd612 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/SelectionPanel.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/SelectionPanel.tsx @@ -9,9 +9,9 @@ import { Button, DeleteActionModal, Tooltip } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types"; import { usePopUp } from "@app/hooks"; @@ -66,9 +66,8 @@ export const SelectionPanel = ({ ); const selectedCount = selectedFolderCount + selectedKeysCount; - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; - const userAvailableEnvs = currentWorkspace?.environments || []; + const { currentProject, projectId } = useProject(); + const userAvailableEnvs = currentProject?.environments || []; const { mutateAsync: deleteBatchSecretV3 } = useDeleteSecretBatch(); const { mutateAsync: deleteFolder } = useDeleteFolder(); @@ -134,7 +133,7 @@ export const SelectionPanel = ({ folderId: folder?.id, path: secretPath, environment: env.slug, - projectId: workspaceId + projectId }); } }) @@ -173,7 +172,7 @@ export const SelectionPanel = ({ processedEntries += secretsToDelete.length; await deleteBatchSecretV3({ secretPath, - workspaceId, + projectId, environment: env.slug, secrets: secretsToDelete }); @@ -281,8 +280,8 @@ export const SelectionPanel = ({ isOpen={popUp.bulkMoveSecrets.isOpen} onOpenChange={(isOpen) => handlePopUpToggle("bulkMoveSecrets", isOpen)} environments={userAvailableEnvs} - projectId={workspaceId} - projectSlug={currentWorkspace.slug} + projectId={projectId} + projectSlug={currentProject.slug} sourceSecretPath={secretPath} secrets={selectedEntries[EntryType.SECRET]} onComplete={resetSelectedEntries} diff --git a/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/components/MoveSecretsDialog/MoveSecretsDialog.tsx b/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/components/MoveSecretsDialog/MoveSecretsDialog.tsx index bb7862f09..30ea57957 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/components/MoveSecretsDialog/MoveSecretsDialog.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/components/SelectionPanel/components/MoveSecretsDialog/MoveSecretsDialog.tsx @@ -30,13 +30,13 @@ import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionCo import { useDebounce } from "@app/hooks"; import { useMoveSecrets } from "@app/hooks/api"; import { useGetProjectSecretsQuickSearch } from "@app/hooks/api/dashboard"; +import { ProjectEnv } from "@app/hooks/api/projects/types"; import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types"; -import { WorkspaceEnv } from "@app/hooks/api/workspace/types"; type Props = { isOpen: boolean; onOpenChange: (isOpen: boolean) => void; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; projectId: string; projectSlug: string; sourceSecretPath: string; @@ -64,7 +64,6 @@ type MoveResults = { const Content = ({ onComplete, secrets, - projectSlug, environments, projectId, sourceSecretPath @@ -189,7 +188,6 @@ const Content = ({ try { const { isDestinationUpdated, isSourceUpdated } = await moveSecrets.mutateAsync({ - projectSlug, shouldOverwrite, sourceEnvironment: environment.slug, sourceSecretPath, diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx index bc82e9b90..77106a57c 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/SecretApprovalsPage.tsx @@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next"; import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { Badge } from "@app/components/v2/Badge"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useGetAccessRequestsCount, useGetSecretApprovalRequestCount } from "@app/hooks/api"; import { AccessApprovalRequest } from "./components/AccessApprovalRequest"; @@ -20,11 +20,10 @@ enum TabSection { export const SecretApprovalsPage = () => { const { t } = useTranslation(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; - const projectSlug = currentWorkspace?.slug || ""; + const { currentProject, projectId } = useProject(); + const projectSlug = currentProject?.slug || ""; const { data: secretApprovalReqCount } = useGetSecretApprovalRequestCount({ - workspaceId: projectId + projectId }); const { data: accessApprovalRequestCount } = useGetAccessRequestsCount({ projectSlug }); const defaultTab = @@ -67,7 +66,7 @@ export const SecretApprovalsPage = () => { - +
diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx index ad905c1f6..ca04665a5 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/AccessApprovalRequest.tsx @@ -39,10 +39,10 @@ import { Badge } from "@app/components/v2/Badge"; import { ProjectPermissionMemberActions, ProjectPermissionSub, + useProject, useProjectPermission, useSubscription, - useUser, - useWorkspace + useUser } from "@app/context"; import { getUserTablePreference, @@ -110,7 +110,7 @@ export const AccessApprovalRequest = ({ const { permission } = useProjectPermission(); const { user } = useUser(); const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: members } = useGetWorkspaceUsers(projectId, true); const membersGroupById = members?.reduce>( @@ -410,7 +410,7 @@ export const AccessApprovalRequest = ({ Select an Environment - {currentWorkspace?.environments.map(({ slug, name }) => ( + {currentProject?.environments.map(({ slug, name }) => ( setEnvFilter((state) => (state === slug ? undefined : slug))} key={`request-filter-${slug}`} diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/components/ReviewAccessModal.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/components/ReviewAccessModal.tsx index e7269298a..a9691724d 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/components/ReviewAccessModal.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/AccessApprovalRequest/components/ReviewAccessModal.tsx @@ -25,7 +25,7 @@ import { Tooltip } from "@app/components/v2"; import { Badge } from "@app/components/v2/Badge"; -import { ProjectPermissionActions, useUser, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, useProject, useUser } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useListWorkspaceGroups, useReviewAccessRequest } from "@app/hooks/api"; import { @@ -102,8 +102,8 @@ export const ReviewAccessRequestModal = ({ const [bypassApproval, setBypassApproval] = useState(false); const [bypassReason, setBypassReason] = useState(""); - const { currentWorkspace } = useWorkspace(); - const { data: groupMemberships = [] } = useListWorkspaceGroups(currentWorkspace?.id || ""); + const { currentProject } = useProject(); + const { data: groupMemberships = [] } = useListWorkspaceGroups(currentProject?.id || ""); const { user } = useUser(); const { popUp, handlePopUpToggle, handlePopUpOpen } = usePopUp(["editRequest"] as const); diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx index 3d292f9a2..bb20643e8 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx @@ -40,9 +40,9 @@ import { import { ProjectPermissionSub, TProjectPermission, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { ProjectPermissionActions } from "@app/context/ProjectPermissionContext/types"; import { @@ -59,14 +59,14 @@ import { import { useGetAccessApprovalPolicies } from "@app/hooks/api/accessApproval/queries"; import { OrderByDirection } from "@app/hooks/api/generic/types"; import { PolicyType } from "@app/hooks/api/policies/enums"; -import { TAccessApprovalPolicy, Workspace } from "@app/hooks/api/types"; +import { Project, TAccessApprovalPolicy } from "@app/hooks/api/types"; import { AccessPolicyForm } from "./components/AccessPolicyModal"; import { ApprovalPolicyRow } from "./components/ApprovalPolicyRow"; import { RemoveApprovalPolicyModal } from "./components/RemoveApprovalPolicyModal"; interface IProps { - workspaceId: string; + projectId: string; } enum PolicyOrderBy { @@ -81,24 +81,24 @@ type PolicyFilters = { environmentIds: string[]; }; -const useApprovalPolicies = (permission: TProjectPermission, currentWorkspace?: Workspace) => { +const useApprovalPolicies = (permission: TProjectPermission, currentProject?: Project) => { const { data: accessPolicies, isPending: isAccessPoliciesLoading } = useGetAccessApprovalPolicies( { - projectSlug: currentWorkspace?.slug as string, + projectSlug: currentProject?.slug as string, options: { enabled: permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval) && - !!currentWorkspace?.slug + !!currentProject?.slug } } ); const { data: secretPolicies, isPending: isSecretPoliciesLoading } = useGetSecretApprovalPolicies( { - workspaceId: currentWorkspace?.id as string, + projectId: currentProject?.id as string, options: { enabled: permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval) && - !!currentWorkspace?.id + !!currentProject?.id } } ); @@ -118,7 +118,7 @@ const useApprovalPolicies = (permission: TProjectPermission, currentWorkspace?: }; }; -export const ApprovalPolicyList = ({ workspaceId }: IProps) => { +export const ApprovalPolicyList = ({ projectId }: IProps) => { const { handlePopUpToggle, handlePopUpOpen, popUp } = usePopUp([ "policyForm", "deletePolicy", @@ -126,14 +126,14 @@ export const ApprovalPolicyList = ({ workspaceId }: IProps) => { ] as const); const { permission } = useProjectPermission(); const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const { data: members } = useGetWorkspaceUsers(workspaceId, true); - const { data: groups } = useListWorkspaceGroups(currentWorkspace?.id || ""); + const { data: members } = useGetWorkspaceUsers(projectId, true); + const { data: groups } = useListWorkspaceGroups(currentProject?.id || ""); const { policies, isLoading: isPoliciesLoading } = useApprovalPolicies( permission, - currentWorkspace + currentProject ); const [filters, setFilters] = useState({ @@ -367,7 +367,7 @@ export const ApprovalPolicyList = ({ workspaceId }: IProps) => { Change Policy Environment - {currentWorkspace.environments.map((env) => ( + {currentProject.environments.map((env) => ( { e.preventDefault(); @@ -466,7 +466,7 @@ export const ApprovalPolicyList = ({ workspaceId }: IProps) => { )} - {!!currentWorkspace && + {!!currentProject && filteredPolicies ?.slice(offset, perPage * page) .map((policy) => ( @@ -497,8 +497,8 @@ export const ApprovalPolicyList = ({ workspaceId }: IProps) => {
handlePopUpToggle("policyForm", isOpen)} members={members} diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx index 856c16ee1..b78b8aa0c 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx @@ -22,7 +22,7 @@ import { Tooltip } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { getMemberLabel } from "@app/helpers/members"; import { policyDetails } from "@app/helpers/policies"; import { @@ -207,10 +207,10 @@ const Form = ({ name: "sequenceApprovers" }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: groups } = useListWorkspaceGroups(projectId); - const availableEnvironments = currentWorkspace?.environments || []; + const availableEnvironments = currentProject?.environments || []; const isAccessPolicyType = watch("policyType") === PolicyType.AccessPolicy; const { mutateAsync: createAccessApprovalPolicy } = useCreateAccessApprovalPolicy(); @@ -246,7 +246,7 @@ const Form = ({ approvers: [...userApprovers, ...groupApprovers], bypassers: bypassers.length > 0 ? bypassers : undefined, environments: environments.map((env) => env.slug), - workspaceId: currentWorkspace?.id || "" + projectId: currentProject?.id || "" }); } else { await createAccessApprovalPolicy({ @@ -302,7 +302,7 @@ const Form = ({ ...data, approvers: [...userApprovers, ...groupApprovers], bypassers: bypassers.length > 0 ? bypassers : undefined, - workspaceId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", environments: environments.map((env) => env.slug) }); } else { diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx index 89a97003e..13147b37b 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/ApprovalPolicyRow.tsx @@ -33,13 +33,13 @@ import { Approver } from "@app/hooks/api/accessApproval/types"; import { TGroupMembership } from "@app/hooks/api/groups/types"; import { EnforcementLevel, PolicyType } from "@app/hooks/api/policies/enums"; import { ApproverType } from "@app/hooks/api/secretApproval/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { TWorkspaceUser } from "@app/hooks/api/users/types"; interface IPolicy { id: string; name: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; projectId?: string; secretPath?: string; approvals: number; diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/RemoveApprovalPolicyModal.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/RemoveApprovalPolicyModal.tsx index d267ffc78..c9f92f6ed 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/RemoveApprovalPolicyModal.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/RemoveApprovalPolicyModal.tsx @@ -4,7 +4,7 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { DeleteActionModal, Spinner } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useDeleteAccessApprovalPolicy, useDeleteSecretApprovalPolicy, @@ -29,18 +29,18 @@ export const RemoveApprovalPolicyModal = ({ const { mutateAsync: deleteSecretApprovalPolicy } = useDeleteSecretApprovalPolicy(); const { mutateAsync: deleteAccessApprovalPolicy } = useDeleteAccessApprovalPolicy(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const handleDeletePolicy = async () => { try { if (policyType === PolicyType.ChangePolicy) { await deleteSecretApprovalPolicy({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, id: policyId }); } else { await deleteAccessApprovalPolicy({ - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, id: policyId }); } @@ -59,14 +59,14 @@ export const RemoveApprovalPolicyModal = ({ const deleteSecretApprovalData = useGetSecretApprovalRequestCount({ policyId, - workspaceId: currentWorkspace.id, + projectId: currentProject.id, options: { enabled: Boolean(policyId) && policyType === PolicyType.ChangePolicy } }); const deleteAccessApprovalData = useGetAccessRequestsCount({ - projectSlug: currentWorkspace.slug, + projectSlug: currentProject.slug, policyId, options: { enabled: Boolean(policyId) && policyType === PolicyType.AccessPolicy diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx index 46b611328..827d14f1e 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/SecretApprovalRequest.tsx @@ -35,9 +35,9 @@ import { ROUTE_PATHS } from "@app/const/routes"; import { ProjectPermissionMemberActions, ProjectPermissionSub, + useProject, useProjectPermission, - useUser, - useWorkspace + useUser } from "@app/context"; import { getUserTablePreference, @@ -58,8 +58,7 @@ import { } from "./components/SecretApprovalRequestChanges"; export const SecretApprovalRequest = () => { - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; + const { currentProject, projectId } = useProject(); const [selectedApprovalId, setSelectedApprovalId] = useState(null); // filters @@ -92,7 +91,7 @@ export const SecretApprovalRequest = () => { isPending: isApprovalRequestLoading, refetch } = useGetSecretApprovalRequests({ - workspaceId, + projectId, status: statusFilter, environment: envFilter, committer: committerFilter, @@ -105,14 +104,14 @@ export const SecretApprovalRequest = () => { const secretApprovalRequests = data?.approvals ?? []; const { data: secretApprovalRequestCount, isSuccess: isSecretApprovalReqCountSuccess } = - useGetSecretApprovalRequestCount({ workspaceId }); + useGetSecretApprovalRequestCount({ projectId }); const { user: userSession } = useUser(); const search = useSearch({ from: ROUTE_PATHS.SecretManager.ApprovalPage.id }); const { permission } = useProjectPermission(); - const { data: members } = useGetWorkspaceUsers(workspaceId); + const { data: members } = useGetWorkspaceUsers(projectId); const isSecretApprovalScreen = Boolean(selectedApprovalId); const { requestId } = search; @@ -143,7 +142,6 @@ export const SecretApprovalRequest = () => { exit={{ opacity: 0, translateX: 30 }} > @@ -241,7 +239,7 @@ export const SecretApprovalRequest = () => { Select an Environment - {currentWorkspace?.environments.map(({ slug, name }) => ( + {currentProject?.environments.map(({ slug, name }) => ( setEnvFilter((state) => (state === slug ? undefined : slug))} key={`request-filter-${slug}`} diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestAction.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestAction.tsx index ee45a442b..9bafb36d4 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestAction.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestAction.tsx @@ -13,6 +13,7 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { Button, Checkbox, FormControl, Input } from "@app/components/v2"; +import { useProject } from "@app/context"; import { usePerformSecretApprovalRequestMerge, useUpdateSecretApprovalRequestStatus @@ -28,7 +29,6 @@ type Props = { canApprove?: boolean; isBypasser: boolean; statusChangeByEmail?: string; - workspaceId: string; enforcementLevel: EnforcementLevel; }; @@ -39,11 +39,11 @@ export const SecretApprovalRequestAction = ({ isMergable, approvals, statusChangeByEmail, - workspaceId, enforcementLevel, canApprove, isBypasser }: Props) => { + const { projectId } = useProject(); const { mutateAsync: performSecretApprovalMerge, isPending: isMerging } = usePerformSecretApprovalRequestMerge(); @@ -62,7 +62,7 @@ export const SecretApprovalRequestAction = ({ try { await performSecretApprovalMerge({ id: approvalRequestId, - workspaceId, + projectId, bypassReason: byPassApproval ? bypassReason : undefined }); createNotification({ @@ -83,7 +83,7 @@ export const SecretApprovalRequestAction = ({ await updateSecretStatusChange({ id: approvalRequestId, status: reqState, - workspaceId + projectId }); createNotification({ type: "success", diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx index 636952c33..0cce12c47 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/SecretApprovalRequest/components/SecretApprovalRequestChanges.tsx @@ -33,7 +33,7 @@ import { TextArea, Tooltip } from "@app/components/v2"; -import { useUser, useWorkspace } from "@app/context"; +import { useProject, useUser } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useGetSecretApprovalRequestDetails, @@ -92,7 +92,6 @@ const getReviewedStatusSymbol = (status?: ApprovalStatus) => { }; type Props = { - workspaceId: string; approvalRequestId: string; onGoBack: () => void; }; @@ -104,13 +103,9 @@ const reviewFormSchema = z.object({ type TReviewFormSchema = z.infer; -export const SecretApprovalRequestChanges = ({ - approvalRequestId, - onGoBack, - workspaceId -}: Props) => { +export const SecretApprovalRequestChanges = ({ approvalRequestId, onGoBack }: Props) => { const { user: userSession } = useUser(); - const { currentWorkspace } = useWorkspace(); + const { projectId } = useProject(); const { data: secretApprovalRequestDetails, isSuccess: isSecretApprovalRequestSuccess, @@ -123,7 +118,7 @@ export const SecretApprovalRequestChanges = ({ ); const { data: secretImports } = useGetSecretImports({ environment: secretApprovalRequestDetails?.environment || "", - projectId: currentWorkspace.id, + projectId, path: approvalSecretPath }); @@ -526,7 +521,6 @@ export const SecretApprovalRequestChanges = ({ isMergable={isMergable} statusChangeByEmail={secretApprovalRequestDetails.statusChangedByUser?.email} enforcementLevel={secretApprovalRequestDetails.policy.enforcementLevel} - workspaceId={workspaceId} />
diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx index a6ae7be62..c926450eb 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx @@ -25,8 +25,8 @@ import { ProjectPermissionActions, ProjectPermissionDynamicSecretActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { ProjectPermissionCommitsActions, @@ -50,10 +50,10 @@ import { useGetProjectSecretsDetails } from "@app/hooks/api/dashboard"; import { DashboardSecretsOrderBy } from "@app/hooks/api/dashboard/types"; import { useGetFolderCommitsCount } from "@app/hooks/api/folderCommits"; import { OrderByDirection } from "@app/hooks/api/generic/types"; +import { ProjectVersion } from "@app/hooks/api/projects/types"; import { PendingAction } from "@app/hooks/api/secretFolders/types"; import { useCreateCommit } from "@app/hooks/api/secrets/mutations"; import { SecretV3RawSanitized } from "@app/hooks/api/types"; -import { ProjectVersion } from "@app/hooks/api/workspace/types"; import { usePathAccessPolicies } from "@app/hooks/usePathAccessPolicies"; import { useResizableColWidth } from "@app/hooks/useResizableColWidth"; import { hasSecretReadValueOrDescribePermission } from "@app/lib/fn/permission"; @@ -94,7 +94,7 @@ const LOADER_TEXT = [ ]; const Page = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate({ from: ROUTE_PATHS.SecretManager.SecretDashboardPage.path }); @@ -142,15 +142,15 @@ const Page = () => { ] as const); // env slug - const workspaceId = currentWorkspace?.id || ""; - const projectSlug = currentWorkspace?.slug || ""; + const projectId = currentProject?.id || ""; + const projectSlug = currentProject?.slug || ""; const secretPath = (routerQueryParams.secretPath as string) || "/"; useEffect(() => { - if (isBatchMode && workspaceId && environment && secretPath) { - loadPendingChanges({ workspaceId, environment, secretPath }); + if (isBatchMode && projectId && environment && secretPath) { + loadPendingChanges({ projectId, environment, secretPath }); } - }, [isBatchMode, workspaceId, environment, secretPath, loadPendingChanges]); + }, [isBatchMode, projectId, environment, secretPath, loadPendingChanges]); const canReadSecret = hasSecretReadValueOrDescribePermission( permission, @@ -240,7 +240,7 @@ const Page = () => { const { togglePopUp } = usePopUpAction(); useEffect(() => { - if (!currentWorkspace?.environments.find((env) => env.slug === environment)) { + if (!currentProject?.environments.find((env) => env.slug === environment)) { createNotification({ text: "No environment found with given slug", type: "error" @@ -248,11 +248,11 @@ const Page = () => { navigate({ to: "/projects/secret-management/$projectId/overview", params: { - projectId: workspaceId + projectId } }); } - }, [currentWorkspace, environment]); + }, [currentProject, environment]); const isResourceTypeFiltered = Object.values(filter.include).some(Boolean); const { @@ -262,7 +262,7 @@ const Page = () => { isFetched } = useGetProjectSecretsDetails({ environment, - projectId: workspaceId, + projectId, secretPath, offset, limit, @@ -316,7 +316,7 @@ const Page = () => { // fetch imported secrets to show user the overriden ones const { data: importedSecrets } = useGetImportedSecretsSingleEnv({ - projectId: workspaceId, + projectId, environment, path: secretPath, options: { @@ -326,13 +326,13 @@ const Page = () => { // fetch tags const { data: tags } = useGetWsTags( - permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags) ? workspaceId : "" + permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags) ? projectId : "" ); const { pathPolicies, hasPathPolicies } = usePathAccessPolicies({ secretPath, environment }); const { data: boardPolicy } = useGetSecretApprovalPolicyOfABoard({ - workspaceId, + projectId, environment, secretPath }); @@ -341,7 +341,7 @@ const Page = () => { const handleCreateCommit = async (changes: PendingChanges, message: string) => { try { await createCommit({ - workspaceId, + projectId, environment, secretPath, pendingChanges: changes, @@ -368,7 +368,7 @@ const Page = () => { fetchNextPage: fetchNextSnapshotList, hasNextPage: hasNextSnapshotListPage } = useGetWorkspaceSnapshotList({ - workspaceId, + projectId, directory: secretPath, environment, isPaused: !popUp.snapshots.isOpen || !canDoReadRollback, @@ -381,7 +381,7 @@ const Page = () => { isFetching: isFolderCommitsCountFetching } = useGetFolderCommitsCount({ directory: secretPath, - workspaceId, + projectId, environment, isPaused: !canReadCommits }); @@ -391,13 +391,13 @@ const Page = () => { isPending: isSnapshotCountLoading, isFetching: isSnapshotCountFetching } = useGetWsSnapshotCount({ - workspaceId, + projectId, environment, directory: secretPath, isPaused: !canDoReadRollback }); - const isPITEnabled = !currentWorkspace?.showSnapshotsLegacy; + const isPITEnabled = !currentProject?.showSnapshotsLegacy; const changesCount = useMemo(() => { return isPITEnabled ? folderCommitsCount : snapshotCount; @@ -416,7 +416,7 @@ const Page = () => { navigate({ to: "/projects/secret-management/$projectId/commits/$environment/$folderId", params: { - projectId: workspaceId, + projectId, folderId, environment }, @@ -647,7 +647,7 @@ const Page = () => { ? change.tags?.map((tag) => ({ id: tag.id, slug: tag.slug, - projectId: workspaceId, + projectId, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), __v: 0 @@ -734,7 +734,7 @@ const Page = () => { const mergedSecrets = getMergedSecretsWithPending(); const mergedFolders = getMergedFoldersWithPending(); - if (!(currentWorkspace?.version === ProjectVersion.V3)) + if (!(currentProject?.version === ProjectVersion.V3)) return (
@@ -794,8 +794,6 @@ const Page = () => { <> { secretImports={imports} isFetching={isDetailsFetching} environment={environment} - workspaceId={workspaceId} + projectId={projectId} secretPath={secretPath} importedSecrets={importedSecrets} /> @@ -966,7 +964,7 @@ const Page = () => { { tags={tags} isVisible={isVisible} environment={environment} - workspaceId={workspaceId} + projectId={projectId} secretPath={secretPath} isProtectedBranch={isProtectedBranch} importedBy={importedBy} @@ -1001,7 +999,7 @@ const Page = () => { @@ -1052,9 +1050,9 @@ const Page = () => { > @@ -1073,10 +1071,10 @@ const Page = () => { )} { { - return `${workspaceId}_${environment}_${secretPath}`; +const generateContextKey = (projectId: string, environment: string, secretPath: string) => { + return `${projectId}_${environment}_${secretPath}`; }; const createBatchModeStore: StateCreator = (set, get) => ({ @@ -272,7 +272,7 @@ const createBatchModeStore: StateCreator addPendingChange: (change: PendingChange, context: BatchContext) => set((state) => { const contextKey = generateContextKey( - context.workspaceId, + context.projectId, context.environment, context.secretPath ); @@ -551,7 +551,7 @@ const createBatchModeStore: StateCreator const currentChanges = contextKey === generateContextKey( - state.currentContext?.workspaceId || context.workspaceId, + state.currentContext?.projectId || context.projectId, state.currentContext?.environment || context.environment, state.currentContext?.secretPath || context.secretPath ) @@ -568,7 +568,7 @@ const createBatchModeStore: StateCreator removePendingChange: (changeId: string, resourceType: string, context: BatchContext) => set((state) => { const contextKey = generateContextKey( - context.workspaceId, + context.projectId, context.environment, context.secretPath ); @@ -593,7 +593,7 @@ const createBatchModeStore: StateCreator state.currentContext && contextKey === generateContextKey( - state.currentContext.workspaceId, + state.currentContext.projectId, state.currentContext.environment, state.currentContext.secretPath ); @@ -606,7 +606,7 @@ const createBatchModeStore: StateCreator loadPendingChanges: (context) => { const contextKey = generateContextKey( - context.workspaceId, + context.projectId, context.environment, context.secretPath ); @@ -626,7 +626,7 @@ const createBatchModeStore: StateCreator clearAllPendingChanges: (context) => { const contextKey = generateContextKey( - context.workspaceId, + context.projectId, context.environment, context.secretPath ); @@ -641,7 +641,7 @@ const createBatchModeStore: StateCreator state.currentContext && contextKey === generateContextKey( - state.currentContext.workspaceId, + state.currentContext.projectId, state.currentContext.environment, state.currentContext.secretPath ); diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx index 9252d71a1..226230c1a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ActionBar.tsx @@ -55,9 +55,9 @@ import { ProjectPermissionActions, ProjectPermissionDynamicSecretActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { ProjectPermissionCommitsActions, @@ -109,9 +109,6 @@ type TSecOverwriteOpt = { update: TParsedEnv; create: TParsedEnv }; type Props = { // switch the secrets type as it gets decrypted after api call environment: string; - // @depreciated will be moving all these details to zustand - workspaceId: string; - projectSlug: string; secretPath?: string; filter: Filter; tags?: WsTag[]; @@ -142,8 +139,6 @@ type Props = { export const ActionBar = ({ environment, - workspaceId, - projectSlug, secretPath = "/", filter, tags = [], @@ -164,6 +159,7 @@ export const ActionBar = ({ hasPathPolicies, onClearFilters }: Props) => { + const { projectId, currentProject } = useProject(); const { handlePopUpOpen, handlePopUpToggle, handlePopUpClose, popUp } = usePopUp([ "addFolder", "addDynamicSecret", @@ -196,7 +192,6 @@ export const ActionBar = ({ const { reset: resetSelectedSecret } = useSelectedSecretActions(); const isMultiSelectActive = Boolean(Object.keys(selectedSecrets).length); - const { currentWorkspace } = useWorkspace(); const { permission } = useProjectPermission(); const handleFolderCreate = async (folderName: string, description: string | null) => { @@ -214,7 +209,7 @@ export const ActionBar = ({ }; addPendingChange(pendingFolderCreate, { - workspaceId, + projectId, environment, secretPath }); @@ -227,7 +222,7 @@ export const ActionBar = ({ name: folderName, path: secretPath, environment, - projectId: workspaceId, + projectId, description }); handlePopUpClose("addFolder"); @@ -247,7 +242,7 @@ export const ActionBar = ({ const handleSecretDownload = async () => { try { const { secrets: localSecrets, imports: localImportedSecrets } = await fetchProjectSecrets({ - workspaceId, + projectId, expandSecretReferences: true, includeImports: true, environment, @@ -317,7 +312,7 @@ export const ActionBar = ({ try { await deleteBatchSecretV3({ secretPath, - workspaceId, + projectId, environment, secrets: bulkDeletedSecrets.map(({ key }) => ({ secretKey: key, type: SecretType.Shared })) }); @@ -348,13 +343,12 @@ export const ActionBar = ({ try { const secretsToMove = Object.values(selectedSecrets); const { isDestinationUpdated, isSourceUpdated } = await moveSecrets({ - projectSlug, shouldOverwrite, sourceEnvironment: environment, sourceSecretPath: secretPath, destinationEnvironment, destinationSecretPath, - projectId: workspaceId, + projectId, secretIds: secretsToMove.map((sec) => sec.id) }); @@ -448,7 +442,7 @@ export const ActionBar = ({ const { secrets: batchSecrets } = await fetchDashboardProjectSecretsByKeys({ secretPath: normalizedPath, environment, - projectId: workspaceId, + projectId, keys: batch }); @@ -566,7 +560,7 @@ export const ActionBar = ({ name: folderName, path: parentPath, environment, - projectId: workspaceId + projectId }); createdFolders.add(fullPath); @@ -598,7 +592,7 @@ export const ActionBar = ({ Object.entries(groupedCreateSecrets).map(([path, secrets]) => createSecretBatch({ secretPath: path, - workspaceId, + projectId, environment, secrets }) @@ -628,7 +622,7 @@ export const ActionBar = ({ Object.entries(groupedUpdateSecrets).map(([path, secrets]) => updateSecretBatch({ secretPath: path, - workspaceId, + projectId, environment, secrets }) @@ -638,13 +632,12 @@ export const ActionBar = ({ // Invalidate appropriate queries to refresh UI queryClient.invalidateQueries({ - queryKey: secretKeys.getProjectSecret({ workspaceId, environment, secretPath }) + queryKey: secretKeys.getProjectSecret({ projectId, environment, secretPath }) }); + queryClient.invalidateQueries({}); + dashboardKeys.getDashboardSecrets({ projectId, secretPath }); queryClient.invalidateQueries({ - queryKey: dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath }) - }); - queryClient.invalidateQueries({ - queryKey: secretApprovalRequestKeys.count({ workspaceId }) + queryKey: secretApprovalRequestKeys.count({ projectId }) }); // Close the modal and show notification @@ -677,8 +670,8 @@ export const ActionBar = ({ className="w-2/5" value={filter.searchFilter} onChange={onSearchChange} - environments={[currentWorkspace.environments.find((env) => env.slug === environment)!]} - projectId={workspaceId} + environments={[currentProject.environments.find((env) => env.slug === environment)!]} + projectId={projectId} tags={tags} />
@@ -1134,8 +1127,8 @@ export const ActionBar = ({ {/* all the side triggers from actions like modals etc */} handlePopUpOpen("upgradePlan")} isOpen={popUp.addSecretImport.isOpen} onClose={() => handlePopUpClose("addSecretImport")} @@ -1144,7 +1137,7 @@ export const ActionBar = ({ handlePopUpToggle("addDynamicSecret", isOpen)} - projectSlug={projectSlug} + projectSlug={currentProject.slug} environments={[{ slug: environment, name: environment, id: "not-used" }]} secretPath={secretPath} isSingleEnvironmentMode @@ -1190,8 +1183,8 @@ export const ActionBar = ({ onToggle={(isOpen) => handlePopUpToggle("replicateFolder", isOpen)} onParsedEnv={handleParsedEnvMultiFolder} environment={environment} - environments={currentWorkspace.environments} - workspaceId={workspaceId} + environments={currentProject.environments} + projectId={projectId} secretPath={secretPath} /> {subscription && ( diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx index 84cf7f7b5..e458f347c 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx @@ -19,7 +19,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; const formSchema = z.object({ provider: z.object({ @@ -63,7 +63,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx index f9ed9967c..a50352f58 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx @@ -20,7 +20,7 @@ import { DynamicSecretAwsIamAuth, DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { MetadataForm } from "../../DynamicSecretListView/MetadataForm"; @@ -112,7 +112,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx index 771523828..6c4ccd65b 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx @@ -18,7 +18,7 @@ import { Tooltip } from "@app/components/v2/Tooltip"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { useGetDynamicSecretProviderData } from "@app/hooks/api/dynamicSecret/queries"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; const formSchema = z.object({ selectedUsers: z.array( @@ -66,7 +66,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx index 8f99d368c..0ef4d092d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx @@ -19,7 +19,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -66,7 +66,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx index fd2eecaa6..1b42dc7e0 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx @@ -24,7 +24,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; // Component for managing scopes and collections within a bucket @@ -265,7 +265,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx index abe14d82d..dd169727d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CreateDynamicSecretForm.tsx @@ -24,7 +24,7 @@ import { AnimatePresence, motion } from "framer-motion"; import { Modal, ModalContent } from "@app/components/v2"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { AwsElastiCacheInputForm } from "./AwsElastiCacheInputForm"; import { AwsIamInputForm } from "./AwsIamInputForm"; @@ -51,7 +51,7 @@ type Props = { isOpen?: boolean; onToggle: (isOpen: boolean) => void; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; secretPath: string; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx index 51dcea68b..390909e81 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx @@ -20,7 +20,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const authMethods = [ @@ -87,7 +87,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GcpIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GcpIamInputForm.tsx index f47273aa1..e7518830d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GcpIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GcpIamInputForm.tsx @@ -8,7 +8,7 @@ import { createNotification } from "@app/components/notifications"; import { Button, FilterableSelect, FormControl, Input } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; const validateTTL = (val: string, ctx: z.RefinementCtx) => { if (!val) return; @@ -49,7 +49,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GithubInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GithubInputForm.tsx index 800bc677a..acac4e0aa 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GithubInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/GithubInputForm.tsx @@ -16,7 +16,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; const formSchema = z.object({ provider: z.object({ @@ -44,7 +44,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx index 2b0838246..945e46777 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx @@ -28,7 +28,7 @@ import { DynamicSecretProviders, KubernetesDynamicSecretCredentialType } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; enum RoleType { @@ -150,7 +150,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx index f2f5c9233..62f8cdd96 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx @@ -16,7 +16,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; enum CredentialType { @@ -89,7 +89,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx index 821730b08..05109e5a3 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx @@ -23,7 +23,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -77,7 +77,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx index 5a89f4649..646755a8f 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx @@ -18,7 +18,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -67,7 +67,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx index f80c374d8..1c2db7d2a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx @@ -18,7 +18,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -71,7 +71,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx index 4d0c51194..06bf4e41a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx @@ -19,7 +19,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -64,7 +64,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx index 413bbe0b6..507e67820 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx @@ -18,7 +18,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -62,7 +62,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx index deea1ada1..38ddbc7f0 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx @@ -19,7 +19,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -64,7 +64,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx index 3120d7cef..30f01c13f 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx @@ -18,7 +18,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; const formSchema = z.object({ @@ -62,7 +62,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx index 050a51754..b0c18fbd3 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx @@ -29,7 +29,7 @@ import { } from "@app/context/OrgPermissionContext/types"; import { gatewaysQueryKeys, useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders, SqlProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; import { MetadataForm } from "../../DynamicSecretListView/MetadataForm"; @@ -110,7 +110,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx index 1ec9f8a0c..63680f524 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/TotpInputForm.tsx @@ -13,7 +13,7 @@ import { } from "@app/components/v2"; import { useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; import { slugSchema } from "@app/lib/schemas"; enum ConfigType { @@ -66,7 +66,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx index d5443b1ed..ca417adb6 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx @@ -27,7 +27,7 @@ import { } from "@app/context/OrgPermissionContext/types"; import { gatewaysQueryKeys, useCreateDynamicSecret } from "@app/hooks/api"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; -import { WorkspaceEnv } from "@app/hooks/api/types"; +import { ProjectEnv } from "@app/hooks/api/types"; const passwordRequirementsSchema = z .object({ @@ -91,7 +91,7 @@ type Props = { onCancel: () => void; secretPath: string; projectSlug: string; - environments: WorkspaceEnv[]; + environments: ProjectEnv[]; isSingleEnvironmentMode?: boolean; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateSecretImportForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateSecretImportForm.tsx index 9bdace648..68d2d8cd0 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateSecretImportForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateSecretImportForm.tsx @@ -14,7 +14,7 @@ import { SelectItem } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; -import { useSubscription, useWorkspace } from "@app/context"; +import { useProject, useSubscription } from "@app/context"; import { useCreateSecretImport } from "@app/hooks/api"; const typeSchema = z.object({ @@ -32,7 +32,7 @@ type TFormSchema = z.infer; type Props = { environment: string; - workspaceId: string; + projectId: string; secretPath?: string; // modal props isOpen?: boolean; @@ -43,7 +43,7 @@ type Props = { export const CreateSecretImportForm = ({ environment, - workspaceId, + projectId, secretPath = "/", isOpen, onClose, @@ -57,8 +57,8 @@ export const CreateSecretImportForm = ({ watch, formState: { isSubmitting } } = useForm({ resolver: zodResolver(typeSchema) }); - const { currentWorkspace } = useWorkspace(); - const environments = currentWorkspace?.environments || []; + const { currentProject } = useProject(); + const environments = currentProject?.environments || []; const selectedEnvironment = watch("environment"); const { subscription } = useSubscription(); @@ -77,7 +77,7 @@ export const CreateSecretImportForm = ({ await createSecretImport({ environment, - projectId: workspaceId, + projectId, path: secretPath, isReplication, import: { diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/MoveSecretsModal.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/MoveSecretsModal.tsx index 606f23fac..05f00315d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/MoveSecretsModal.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/MoveSecretsModal.tsx @@ -12,7 +12,7 @@ import { SelectItem } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { UsePopUpState } from "@app/hooks/usePopUp"; type Props = { @@ -47,8 +47,8 @@ export const MoveSecretsModal = ({ popUp, handlePopUpToggle, onMoveApproved }: P formState: { isSubmitting } } = useForm({ resolver: zodResolver(formSchema) }); - const { currentWorkspace } = useWorkspace(); - const environments = currentWorkspace?.environments || []; + const { currentProject } = useProject(); + const environments = currentProject?.environments || []; const selectedEnvironment = watch("environment"); const handleFormSubmit = (data: TFormSchema) => { diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/ReplicateFolderFromBoard.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/ReplicateFolderFromBoard.tsx index 339612a89..5e4cee953 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/ReplicateFolderFromBoard.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/ReplicateFolderFromBoard.tsx @@ -48,7 +48,7 @@ type Props = { env: Record> ) => void; environments?: { name: string; slug: string }[]; - workspaceId: string; + projectId: string; environment: string; secretPath: string; }; @@ -64,7 +64,7 @@ type SecretStructure = { export const ReplicateFolderFromBoard = ({ environments = [], - workspaceId, + projectId, isOpen, onToggle, onParsedEnv @@ -82,14 +82,14 @@ export const ReplicateFolderFromBoard = ({ const [debouncedEnvCopySecretPath] = useDebounce(envCopySecPath); const { data: accessibleSecrets } = useGetAccessibleSecrets({ - projectId: workspaceId, + projectId, secretPath: "/", environment: selectedEnvSlug.slug, recursive: true, filterByAction: shouldIncludeValues ? ProjectPermissionSecretActions.ReadValue : ProjectPermissionSecretActions.DescribeSecret, - options: { enabled: Boolean(workspaceId) && Boolean(selectedEnvSlug) && isOpen } + options: { enabled: Boolean(projectId) && Boolean(selectedEnvSlug) && isOpen } }); const restructureSecrets = useMemo(() => { diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx index c3f5e74ee..f81cd7b2d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/CommitForm/CommitForm.tsx @@ -25,14 +25,14 @@ interface CommitFormProps { onCommit: (changes: PendingChanges, commitMessage: string) => Promise; isCommitting?: boolean; environment: string; - workspaceId: string; + projectId: string; secretPath: string; } interface ResourceChangeProps { change: PendingChange; environment: string; - workspaceId: string; + projectId: string; secretPath: string; } @@ -237,7 +237,7 @@ const RenderFolderChanges = ({ onDiscard, change }: RenderResourceProps) => { const ResourceChange: React.FC = ({ change, environment, - workspaceId, + projectId, secretPath }) => { const { removePendingChange } = useBatchModeActions(); @@ -245,7 +245,7 @@ const ResourceChange: React.FC = ({ const handleDeletePending = useCallback( (changeType: string, id: string) => { removePendingChange(id, changeType, { - workspaceId, + projectId, environment, secretPath }); @@ -272,7 +272,7 @@ export const CommitForm: React.FC = ({ onCommit, isCommitting = false, environment, - workspaceId, + projectId, secretPath }) => { const { isBatchMode, pendingChanges, totalChangesCount } = useBatchMode(); @@ -291,7 +291,7 @@ export const CommitForm: React.FC = ({ } await onCommit(pendingChanges, commitMessage); clearAllPendingChanges({ - workspaceId, + projectId, environment, secretPath }); @@ -335,9 +335,7 @@ export const CommitForm: React.FC = ({
); diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/AddEnvironmentModal.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/AddEnvironmentModal.tsx index 0832dfe9d..611504a14 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/AddEnvironmentModal.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/AddEnvironmentModal.tsx @@ -4,15 +4,15 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalClose, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateWsEnvironment } from "@app/hooks/api"; -import { WorkspaceEnv } from "@app/hooks/api/workspace/types"; +import { ProjectEnv } from "@app/hooks/api/projects/types"; import { slugSchema } from "@app/lib/schemas"; type Props = { isOpen: boolean; onOpenChange: (isOpen: boolean) => void; - onComplete?: (environment: WorkspaceEnv) => void; + onComplete?: (environment: ProjectEnv) => void; }; const schema = z.object({ @@ -25,11 +25,11 @@ const schema = z.object({ export type FormData = z.infer; type ContentProps = { - onComplete: (environment: WorkspaceEnv) => void; + onComplete: (environment: ProjectEnv) => void; }; const Content = ({ onComplete }: ContentProps) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync, isPending } = useCreateWsEnvironment(); const { control, handleSubmit } = useForm({ resolver: zodResolver(schema) @@ -37,10 +37,10 @@ const Content = ({ onComplete }: ContentProps) => { const onFormSubmit = async ({ environmentName, environmentSlug }: FormData) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; const env = await mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, name: environmentName, slug: environmentSlug }); diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentSection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentSection.tsx index 34acf0c7b..016266e69 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentSection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentSection.tsx @@ -8,9 +8,9 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, + useProject, useProjectPermission, - useSubscription, - useWorkspace + useSubscription } from "@app/context"; import { useDeleteWsEnvironment } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -21,14 +21,14 @@ import { UpdateEnvironmentModal } from "./UpdateEnvironmentModal"; export const EnvironmentSection = () => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { permission } = useProjectPermission(); const deleteWsEnvironment = useDeleteWsEnvironment(); const isMoreEnvironmentsAllowed = - subscription?.environmentLimit && currentWorkspace?.environments - ? currentWorkspace.environments.length < subscription.environmentLimit + subscription?.environmentLimit && currentProject?.environments + ? currentProject.environments.length < subscription.environmentLimit : true; const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ @@ -40,10 +40,10 @@ export const EnvironmentSection = () => { const onEnvDeleteSubmit = async (id: string) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await deleteWsEnvironment.mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, id }); diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentTable.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentTable.tsx index 0626db281..0908d8377 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentTable.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/EnvironmentTable.tsx @@ -18,8 +18,8 @@ import { import { ProjectPermissionActions, ProjectPermissionSub, - useSubscription, - useWorkspace + useProject, + useSubscription } from "@app/context"; import { useUpdateWsEnvironment } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -40,17 +40,17 @@ type Props = { }; export const EnvironmentTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { subscription } = useSubscription(); const updateEnvironment = useUpdateWsEnvironment(); const handleReorderEnv = async (id: string, position: number) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await updateEnvironment.mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, id, position }); @@ -69,13 +69,13 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => { }; const isMoreEnvironmentsAllowed = - subscription?.environmentLimit && currentWorkspace?.environments - ? currentWorkspace.environments.length <= subscription.environmentLimit + subscription?.environmentLimit && currentProject?.environments + ? currentProject.environments.length <= subscription.environmentLimit : true; const environmentsOverPlanLimit = - subscription?.environmentLimit && currentWorkspace?.environments - ? Math.max(0, currentWorkspace.environments.length - subscription.environmentLimit) + subscription?.environmentLimit && currentProject?.environments + ? Math.max(0, currentProject.environments.length - subscription.environmentLimit) : 0; return ( @@ -89,7 +89,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => { - {currentWorkspace.environments.map(({ name, slug, id }, pos) => ( + {currentProject.environments.map(({ name, slug, id }, pos) => ( {name} {slug} @@ -102,15 +102,12 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => { - handleReorderEnv( - id, - Math.min(currentWorkspace.environments.length, pos + 2) - ) + handleReorderEnv(id, Math.min(currentProject.environments.length, pos + 2)) } colorSchema="primary" variant="plain" ariaLabel="update" - isDisabled={pos === currentWorkspace.environments.length - 1 || !isAllowed} + isDisabled={pos === currentProject.environments.length - 1 || !isAllowed} > @@ -183,7 +180,7 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => { ))} - {currentWorkspace.environments?.length === 0 && ( + {currentProject.environments?.length === 0 && ( diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/UpdateEnvironmentModal.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/UpdateEnvironmentModal.tsx index f40091303..e2d64ee72 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/UpdateEnvironmentModal.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/EnvironmentSection/UpdateEnvironmentModal.tsx @@ -4,7 +4,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useUpdateWsEnvironment } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; import { slugSchema } from "@app/lib/schemas"; @@ -23,7 +23,7 @@ const schema = z.object({ export type FormData = z.infer; export const UpdateEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync, isPending } = useUpdateWsEnvironment(); const { control, handleSubmit, reset } = useForm({ resolver: zodResolver(schema), @@ -34,10 +34,10 @@ export const UpdateEnvironmentModal = ({ popUp, handlePopUpClose, handlePopUpTog const onFormSubmit = async ({ name, slug }: FormData) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await mutateAsync({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, name, slug, id: oldEnvId diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/PointInTimeVersionLimitSection/PointInTimeVersionLimitSection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/PointInTimeVersionLimitSection/PointInTimeVersionLimitSection.tsx index 288500d26..bd8d15887 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/PointInTimeVersionLimitSection/PointInTimeVersionLimitSection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/PointInTimeVersionLimitSection/PointInTimeVersionLimitSection.tsx @@ -4,9 +4,9 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; +import { useUpdateProject } from "@app/hooks/api"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; -import { useUpdateWorkspaceVersionLimit } from "@app/hooks/api/workspace/queries"; const formSchema = z.object({ pitVersionLimit: z.coerce.number().min(1).max(100) @@ -15,9 +15,9 @@ const formSchema = z.object({ type TForm = z.infer; export const PointInTimeVersionLimitSection = () => { - const { mutateAsync: updatePitVersion } = useUpdateWorkspaceVersionLimit(); + const { mutateAsync: updateProject } = useUpdateProject(); - const { currentWorkspace } = useWorkspace(); + const { currentProject, projectId } = useProject(); const { membership } = useProjectPermission(); const { @@ -27,17 +27,17 @@ export const PointInTimeVersionLimitSection = () => { } = useForm({ resolver: zodResolver(formSchema), values: { - pitVersionLimit: currentWorkspace?.pitVersionLimit || 10 + pitVersionLimit: currentProject?.pitVersionLimit || 10 } }); - if (!currentWorkspace) return null; + if (!currentProject) return null; const handleVersionLimitSubmit = async ({ pitVersionLimit }: TForm) => { try { - await updatePitVersion({ + await updateProject({ pitVersionLimit, - projectSlug: currentWorkspace.slug + projectId }); createNotification({ diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/SecretDetectionIgnoreValuesSection/SecretDetectionIgnoreValuesSection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/SecretDetectionIgnoreValuesSection/SecretDetectionIgnoreValuesSection.tsx index 5869aa127..a7c6bbc36 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/SecretDetectionIgnoreValuesSection/SecretDetectionIgnoreValuesSection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/SecretDetectionIgnoreValuesSection/SecretDetectionIgnoreValuesSection.tsx @@ -7,7 +7,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, IconButton, Input } from "@app/components/v2"; -import { useProjectPermission, useWorkspace } from "@app/context"; +import { useProject, useProjectPermission } from "@app/context"; import { useUpdateProject } from "@app/hooks/api"; import { ProjectMembershipRole } from "@app/hooks/api/roles/types"; @@ -23,7 +23,7 @@ const formSchema = z.object({ type TForm = z.infer; export const SecretDetectionIgnoreValuesSection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { membership } = useProjectPermission(); const { mutateAsync: updateProject } = useUpdateProject(); @@ -45,19 +45,19 @@ export const SecretDetectionIgnoreValuesSection = () => { }); useEffect(() => { - const existingIgnoreValues = currentWorkspace?.secretDetectionIgnoreValues || []; + const existingIgnoreValues = currentProject?.secretDetectionIgnoreValues || []; reset({ ignoreValues: existingIgnoreValues.length > 0 ? existingIgnoreValues.map((value) => ({ value })) : [{ value: "" }] // Show one empty field by default }); - }, [currentWorkspace?.secretDetectionIgnoreValues, reset]); + }, [currentProject?.secretDetectionIgnoreValues, reset]); const handleIgnoreValuesSubmit = async ({ ignoreValues }: TForm) => { try { await updateProject({ - projectID: currentWorkspace.id, + projectId: currentProject.id, secretDetectionIgnoreValues: ignoreValues.map((item) => item.value) }); @@ -75,7 +75,7 @@ export const SecretDetectionIgnoreValuesSection = () => { const isAdmin = membership.roles.includes(ProjectMembershipRole.Admin); - if (!currentWorkspace) return null; + if (!currentProject) return null; return (
diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/SecretSharingSection/SecretSharingSection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/SecretSharingSection/SecretSharingSection.tsx index 0dd145e41..83639d204 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/SecretSharingSection/SecretSharingSection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/SecretSharingSection/SecretSharingSection.tsx @@ -3,11 +3,11 @@ import { useState } from "react"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Checkbox } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; -import { useUpdateProject } from "@app/hooks/api/workspace/queries"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; +import { useUpdateProject } from "@app/hooks/api/projects/queries"; export const SecretSharingSection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: updateProject } = useUpdateProject(); const [isLoading, setIsLoading] = useState(false); @@ -16,13 +16,13 @@ export const SecretSharingSection = () => { setIsLoading(true); try { - if (!currentWorkspace?.id) { + if (!currentProject?.id) { setIsLoading(false); return; } await updateProject({ - projectID: currentWorkspace.id, + projectId: currentProject.id, secretSharing: state }); @@ -50,7 +50,7 @@ export const SecretSharingSection = () => { handleToggle(state as boolean)} > This feature enables your project members to securely share secrets. diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/SecretSnapshotsLegacySection/SecretSnapshotsLegacySection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/SecretSnapshotsLegacySection/SecretSnapshotsLegacySection.tsx index 69c2bcbfd..90b866e96 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/SecretSnapshotsLegacySection/SecretSnapshotsLegacySection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/SecretSnapshotsLegacySection/SecretSnapshotsLegacySection.tsx @@ -3,11 +3,11 @@ import { useState } from "react"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Checkbox } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; -import { useUpdateProject } from "@app/hooks/api/workspace/queries"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; +import { useUpdateProject } from "@app/hooks/api/projects/queries"; export const SecretSnapshotsLegacySection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync: updateProject } = useUpdateProject(); const [isLoading, setIsLoading] = useState(false); @@ -16,13 +16,13 @@ export const SecretSnapshotsLegacySection = () => { setIsLoading(true); try { - if (!currentWorkspace?.id) { + if (!currentProject?.id) { setIsLoading(false); return; } await updateProject({ - projectID: currentWorkspace.id, + projectId: currentProject.id, showSnapshotsLegacy: state }); @@ -50,7 +50,7 @@ export const SecretSnapshotsLegacySection = () => { handleToggle(state as boolean)} > This feature enables your project members to view secret snapshots in the legacy diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/AddSecretTagModal.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/AddSecretTagModal.tsx index 96c667050..1d4c8e492 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/AddSecretTagModal.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/AddSecretTagModal.tsx @@ -4,7 +4,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalClose, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateWsTag } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; import { slugSchema } from "@app/lib/schemas"; @@ -27,7 +27,7 @@ type Props = { }; export const AddSecretTagModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const createWsTag = useCreateWsTag(); const { control, @@ -40,10 +40,10 @@ export const AddSecretTagModal = ({ popUp, handlePopUpClose, handlePopUpToggle } const onFormSubmit = async ({ slug }: FormData) => { try { - if (!currentWorkspace?.id) return; + if (!currentProject?.id) return; await createWsTag.mutateAsync({ - workspaceID: currentWorkspace?.id, + projectId: currentProject?.id, tagSlug: slug, tagColor: "" }); @@ -73,7 +73,7 @@ export const AddSecretTagModal = ({ popUp, handlePopUpClose, handlePopUpToggle } }} >
diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsSection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsSection.tsx index 26be8eb17..55da0f03b 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsSection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsSection.tsx @@ -7,8 +7,8 @@ import { Button, DeleteActionModal } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, - useProjectPermission, - useWorkspace + useProject, + useProjectPermission } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteWsTag } from "@app/hooks/api"; @@ -23,7 +23,7 @@ export const SecretTagsSection = (): JSX.Element => { "CreateSecretTag", "deleteTagConfirmation" ] as const); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { permission } = useProjectPermission(); const deleteWsTag = useDeleteWsTag(); @@ -31,7 +31,7 @@ export const SecretTagsSection = (): JSX.Element => { const onDeleteApproved = async () => { try { await deleteWsTag.mutateAsync({ - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", tagID: (popUp?.deleteTagConfirmation?.data as DeleteModalData)?.id }); diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsTable.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsTable.tsx index d0633eb12..15d8ef7cb 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsTable.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/SecretTagsSection/SecretTagsTable.tsx @@ -24,7 +24,7 @@ import { THead, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { getUserTablePreference, PreferenceKey, @@ -53,8 +53,8 @@ enum TagsOrderBy { } export const SecretTagsTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); - const { data: tags = [], isPending } = useGetWsTags(currentWorkspace?.id ?? ""); + const { currentProject } = useProject(); + const { data: tags = [], isPending } = useGetWsTags(currentProject?.id ?? ""); const { search, diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/WebhooksTab/WebhooksTab.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/WebhooksTab/WebhooksTab.tsx index 8c8d75f47..79fc7aafc 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/WebhooksTab/WebhooksTab.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/WebhooksTab/WebhooksTab.tsx @@ -18,7 +18,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { withProjectPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { @@ -35,14 +35,14 @@ export const WebhooksTab = withProjectPermission( () => { const { t } = useTranslation(); - const { currentWorkspace } = useWorkspace(); - const workspaceId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ "addWebhook", "deleteWebhook" ] as const); - const { data: webhooks, isPending: isWebhooksLoading } = useGetWebhooks(workspaceId); + const { data: webhooks, isPending: isWebhooksLoading } = useGetWebhooks(projectId); // mutation const { mutateAsync: createWebhook } = useCreateWebhook(); @@ -62,7 +62,7 @@ export const WebhooksTab = withProjectPermission( try { await createWebhook({ ...data, - workspaceId + projectId }); handlePopUpClose("addWebhook"); createNotification({ @@ -82,7 +82,7 @@ export const WebhooksTab = withProjectPermission( try { await updateWebhook({ webhookId, - workspaceId, + projectId, isDisabled }); createNotification({ @@ -103,7 +103,7 @@ export const WebhooksTab = withProjectPermission( const webhookId = popUp?.deleteWebhook?.data as string; await deleteWebhook({ webhookId, - workspaceId + projectId }); handlePopUpClose("deleteWebhook"); createNotification({ @@ -123,7 +123,7 @@ export const WebhooksTab = withProjectPermission( try { await testWebhook({ webhookId, - workspaceId + projectId }); createNotification({ type: "success", @@ -302,7 +302,7 @@ export const WebhooksTab = withProjectPermission(
handlePopUpToggle("addWebhook", isOpen)} onCreateWebhook={handleWebhookCreate} diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/WorkflowIntegrationTab.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/WorkflowIntegrationTab.tsx index 5b5f92bbb..ce8a3a70c 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/WorkflowIntegrationTab.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/WorkflowIntegrationTab.tsx @@ -15,7 +15,7 @@ import { THead, Tr } from "@app/components/v2"; -import { OrgPermissionActions, OrgPermissionSubjects, useWorkspace } from "@app/context"; +import { OrgPermissionActions, OrgPermissionSubjects, useProject } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteProjectWorkflowIntegration, @@ -47,16 +47,16 @@ export const WorkflowIntegrationTab = () => { "editIntegration" ] as const); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: slackConfig, isPending: isSlackConfigLoading } = useGetWorkspaceWorkflowIntegrationConfig({ - workspaceId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: WorkflowIntegrationPlatform.SLACK }); const { data: microsoftTeamsConfig, isPending: isMicrosoftTeamsConfigLoading } = useGetWorkspaceWorkflowIntegrationConfig({ - workspaceId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS }); @@ -66,12 +66,12 @@ export const WorkflowIntegrationTab = () => { integrationType: WorkflowIntegrationPlatform, integrationId: string ) => { - if (!currentWorkspace.id) { + if (!currentProject.id) { return; } await deleteIntegration({ - projectId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: integrationType, integrationId }); diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/AddWorkflowIntegrationModal.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/AddWorkflowIntegrationModal.tsx index 8601c1c02..28a3c83d3 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/AddWorkflowIntegrationModal.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/AddWorkflowIntegrationModal.tsx @@ -6,7 +6,7 @@ import { AnimatePresence, motion } from "framer-motion"; import { twMerge } from "tailwind-merge"; import { Modal, ModalContent } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useGetWorkspaceWorkflowIntegrationConfig } from "@app/hooks/api"; import { WorkflowIntegrationPlatform } from "@app/hooks/api/workflowIntegrations/types"; @@ -40,14 +40,14 @@ export const AddWorkflowIntegrationModal = ({ isOpen, onToggle }: Props) => { const [wizardStep, setWizardStep] = useState(WizardSteps.SelectPlatform); const [selectedPlatform, setSelectedPlatform] = useState(null); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: microsoftTeamsConfig } = useGetWorkspaceWorkflowIntegrationConfig({ - workspaceId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS }); const { data: slackConfig } = useGetWorkspaceWorkflowIntegrationConfig({ - workspaceId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: WorkflowIntegrationPlatform.SLACK }); diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/MicrosoftTeamsIntegrationForm.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/MicrosoftTeamsIntegrationForm.tsx index aab932b8d..2bfe8cece 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/MicrosoftTeamsIntegrationForm.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/MicrosoftTeamsIntegrationForm.tsx @@ -19,7 +19,7 @@ import { SelectItem, Switch } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub @@ -95,13 +95,13 @@ type Props = { }; export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: microsoftTeamsConfig } = useGetWorkspaceWorkflowIntegrationConfig({ - workspaceId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: WorkflowIntegrationPlatform.MICROSOFT_TEAMS }); const { data: microsoftTeamsIntegrations } = useGetMicrosoftTeamsIntegrations( - currentWorkspace?.orgId + currentProject?.orgId ); const { mutateAsync: updateProjectMicrosoftTeamsConfig } = @@ -131,12 +131,12 @@ export const MicrosoftTeamsIntegrationForm = ({ onClose }: Props) => { const handleIntegrationSave = async (data: TMicrosoftTeamsConfigForm) => { try { - if (!currentWorkspace) { + if (!currentProject) { return; } await updateProjectMicrosoftTeamsConfig({ - workspaceId: currentWorkspace.id, + projectId: currentProject.id, isAccessRequestNotificationEnabled: data.isAccessRequestNotificationEnabled, isSecretRequestNotificationEnabled: data.isSecretRequestNotificationEnabled, ...(data.isAccessRequestNotificationEnabled && { diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx index 6bcaa6ac1..26cae7f61 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/WorkflowIntegrationSection/components/SlackIntegrationForm.tsx @@ -19,7 +19,7 @@ import { SelectItem, Switch } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { ProjectPermissionActions, ProjectPermissionSub @@ -47,12 +47,12 @@ type Props = { }; export const SlackIntegrationForm = ({ onClose }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: slackConfig } = useGetWorkspaceWorkflowIntegrationConfig({ - workspaceId: currentWorkspace?.id ?? "", + projectId: currentProject?.id ?? "", integration: WorkflowIntegrationPlatform.SLACK }); - const { data: workflowIntegrations } = useGetWorkflowIntegrations(currentWorkspace?.orgId); + const { data: workflowIntegrations } = useGetWorkflowIntegrations(currentProject?.orgId); const { mutateAsync: updateProjectSlackConfig } = useUpdateProjectWorkflowIntegrationConfig(); const slackIntegrations = workflowIntegrations?.filter( @@ -77,13 +77,13 @@ export const SlackIntegrationForm = ({ onClose }: Props) => { const handleIntegrationSave = async (data: TSlackConfigForm) => { try { - if (!currentWorkspace) { + if (!currentProject) { return; } await updateProjectSlackConfig({ ...data, - workspaceId: currentWorkspace.id, + projectId: currentProject.id, integration: WorkflowIntegrationPlatform.SLACK, integrationId: data.slackIntegrationId, accessRequestChannels: data.accessRequestChannels.filter(Boolean).join(", "), diff --git a/frontend/src/pages/secret-manager/integrations/AwsParameterStoreAuthorizePage/AwsParameterStoreAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/AwsParameterStoreAuthorizePage/AwsParameterStoreAuthorizePage.tsx index e67e1e328..16493ad0f 100644 --- a/frontend/src/pages/secret-manager/integrations/AwsParameterStoreAuthorizePage/AwsParameterStoreAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AwsParameterStoreAuthorizePage/AwsParameterStoreAuthorizePage.tsx @@ -16,7 +16,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; enum AwsAuthType { @@ -40,7 +40,7 @@ type TForm = z.infer; export const AWSParameterStoreAuthorizeIntegrationPage = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync } = useSaveIntegrationAccessToken(); const { control, handleSubmit, formState, watch } = useForm({ @@ -55,7 +55,7 @@ export const AWSParameterStoreAuthorizeIntegrationPage = () => { const handleFormSubmit = async (data: TForm) => { try { const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "aws-parameter-store", ...(data.type === AwsAuthType.AssumeRole ? { @@ -70,7 +70,7 @@ export const AWSParameterStoreAuthorizeIntegrationPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/aws-parameter-store/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/AwsParameterStoreConfigurePage/AwsParamterStoreConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/AwsParameterStoreConfigurePage/AwsParamterStoreConfigurePage.tsx index bbdd2d71b..5b5d97f6a 100644 --- a/frontend/src/pages/secret-manager/integrations/AwsParameterStoreConfigurePage/AwsParamterStoreConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AwsParameterStoreConfigurePage/AwsParamterStoreConfigurePage.tsx @@ -26,7 +26,7 @@ import { Tabs } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; import { useGetIntegrationAuthAwsKmsKeys } from "@app/hooks/api/integrationAuth/queries"; @@ -77,7 +77,7 @@ export const AWSParameterStoreConfigurePage = () => { from: ROUTE_PATHS.SecretManager.Integratons.AwsParameterStoreConfigurePage.id, select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: integrationAuth, isPending: isintegrationAuthLoading } = useGetIntegrationAuthById( (integrationAuthId as string) ?? "" @@ -97,11 +97,11 @@ export const AWSParameterStoreConfigurePage = () => { const [kmsKeyId, setKmsKeyId] = useState(""); useEffect(() => { - if (currentWorkspace) { - setSelectedSourceEnvironment(currentWorkspace.environments[0].slug); + if (currentProject) { + setSelectedSourceEnvironment(currentProject.environments[0].slug); setSelectedAWSRegion(awsRegions[0].slug); } - }, [currentWorkspace]); + }, [currentProject]); const { data: integrationAuthAwsKmsKeys, isPending: isIntegrationAuthAwsKmsKeysLoading } = useGetIntegrationAuthAwsKmsKeys({ @@ -158,7 +158,7 @@ export const AWSParameterStoreConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -226,7 +226,7 @@ export const AWSParameterStoreConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { ; export const AWSSecretManagerAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, formState, watch } = useForm({ resolver: zodResolver(formSchema), @@ -54,7 +54,7 @@ export const AWSSecretManagerAuthorizePage = () => { const handleFormSubmit = async (data: TForm) => { try { const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "aws-secret-manager", ...(data.type === AwsAuthType.AssumeRole ? { @@ -68,7 +68,7 @@ export const AWSSecretManagerAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/aws-secret-manager/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/AwsSecretManagerConfigurePage/AwsSecretManagerConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/AwsSecretManagerConfigurePage/AwsSecretManagerConfigurePage.tsx index bd73fc596..6c82b7edd 100644 --- a/frontend/src/pages/secret-manager/integrations/AwsSecretManagerConfigurePage/AwsSecretManagerConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AwsSecretManagerConfigurePage/AwsSecretManagerConfigurePage.tsx @@ -30,7 +30,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; import { useGetIntegrationAuthAwsKmsKeys } from "@app/hooks/api/integrationAuth/queries"; @@ -150,7 +150,7 @@ export const AwsSecretManagerConfigurePage = () => { select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: integrationAuth, isPending: isintegrationAuthLoading } = useGetIntegrationAuthById( (integrationAuthId as string) ?? "" ); @@ -162,11 +162,11 @@ export const AwsSecretManagerConfigurePage = () => { }); useEffect(() => { - if (currentWorkspace) { - setValue("sourceEnvironment", currentWorkspace.environments[0].slug); + if (currentProject) { + setValue("sourceEnvironment", currentProject.environments[0].slug); setValue("awsRegion", awsRegions[0].slug); } - }, [currentWorkspace]); + }, [currentProject]); const handleButtonClick = async ({ secretName, @@ -206,7 +206,7 @@ export const AwsSecretManagerConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -286,7 +286,7 @@ export const AwsSecretManagerConfigurePage = () => { field.onChange(val); }} > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { isError={Boolean(error)} > { from: ROUTE_PATHS.SecretManager.Integratons.AzureAppConfigurationsConfigurePage.id, select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const { data: workspace } = useGetWorkspaceById(currentWorkspace.id); + const { data: workspace } = useGetWorkspaceById(currentProject.id); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); useEffect(() => { @@ -133,7 +133,7 @@ export const AzureAppConfigurationConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations diff --git a/frontend/src/pages/secret-manager/integrations/AzureAppConfigurationOauthCallbackPage/AzureAppConfigurationOauthCallbackPage.tsx b/frontend/src/pages/secret-manager/integrations/AzureAppConfigurationOauthCallbackPage/AzureAppConfigurationOauthCallbackPage.tsx index d15fea903..046fac913 100644 --- a/frontend/src/pages/secret-manager/integrations/AzureAppConfigurationOauthCallbackPage/AzureAppConfigurationOauthCallbackPage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AzureAppConfigurationOauthCallbackPage/AzureAppConfigurationOauthCallbackPage.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useAuthorizeIntegration } from "@app/hooks/api"; export const AzureAppConfigurationOauthCallbackPage = () => { @@ -12,7 +12,7 @@ export const AzureAppConfigurationOauthCallbackPage = () => { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.AzureAppConfigurationsOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -22,7 +22,7 @@ export const AzureAppConfigurationOauthCallbackPage = () => { localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, integration: "azure-app-configuration" }); @@ -30,7 +30,7 @@ export const AzureAppConfigurationOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/azure-app-configuration/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/AzureDevopsAuthorizePage/AzureDevopsAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/AzureDevopsAuthorizePage/AzureDevopsAuthorizePage.tsx index 25cc9c617..4a03c9c3e 100644 --- a/frontend/src/pages/secret-manager/integrations/AzureDevopsAuthorizePage/AzureDevopsAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AzureDevopsAuthorizePage/AzureDevopsAuthorizePage.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const AzureDevopsAuthorizePage = () => { @@ -16,7 +16,7 @@ export const AzureDevopsAuthorizePage = () => { const [devopsOrgName, setDevopsOrgName] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [isLoading, setIsLoading] = useState(false); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const handleButtonClick = async () => { try { @@ -31,7 +31,7 @@ export const AzureDevopsAuthorizePage = () => { localStorage.setItem("azure-devops-org-name", devopsOrgName); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "azure-devops", accessToken: btoa(`:${apiKey}`) // This is a base64 encoding of the API key without any username }); @@ -41,7 +41,7 @@ export const AzureDevopsAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/azure-devops/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/AzureDevopsConfigurePage/AzureDevopsConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/AzureDevopsConfigurePage/AzureDevopsConfigurePage.tsx index b06859e1f..3d092fa26 100644 --- a/frontend/src/pages/secret-manager/integrations/AzureDevopsConfigurePage/AzureDevopsConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AzureDevopsConfigurePage/AzureDevopsConfigurePage.tsx @@ -14,13 +14,13 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; -import { useGetWorkspaceById } from "@app/hooks/api/workspace"; +import { useGetWorkspaceById } from "@app/hooks/api/projects"; import { IntegrationsListPageTabs } from "@app/types/integrations"; export const AzureDevopsConfigurePage = () => { @@ -31,9 +31,9 @@ export const AzureDevopsConfigurePage = () => { from: ROUTE_PATHS.SecretManager.Integratons.AzureDevopsConfigurePage.id, select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const { data: workspace } = useGetWorkspaceById(currentWorkspace.id); + const { data: workspace } = useGetWorkspaceById(currentProject.id); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuthApps } = useGetIntegrationAuthApps({ integrationAuthId: (integrationAuthId as string) ?? "", @@ -82,7 +82,7 @@ export const AzureDevopsConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations diff --git a/frontend/src/pages/secret-manager/integrations/AzureKeyVaultConfigurePage/AzureKeyVaultConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/AzureKeyVaultConfigurePage/AzureKeyVaultConfigurePage.tsx index e5ccd3dfa..91f0d5440 100644 --- a/frontend/src/pages/secret-manager/integrations/AzureKeyVaultConfigurePage/AzureKeyVaultConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/AzureKeyVaultConfigurePage/AzureKeyVaultConfigurePage.tsx @@ -11,11 +11,11 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; import { IntegrationSyncBehavior } from "@app/hooks/api/integrations/types"; -import { useGetWorkspaceById } from "@app/hooks/api/workspace"; +import { useGetWorkspaceById } from "@app/hooks/api/projects"; import { IntegrationsListPageTabs } from "@app/types/integrations"; const initialSyncBehaviors = [ @@ -38,9 +38,9 @@ export const AzureKeyVaultConfigurePage = () => { from: ROUTE_PATHS.SecretManager.Integratons.AzureKeyVaultConfigurePage.id, select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); - const { data: workspace } = useGetWorkspaceById(currentWorkspace.id); + const { data: workspace } = useGetWorkspaceById(currentProject.id); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); @@ -90,7 +90,7 @@ export const AzureKeyVaultConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations diff --git a/frontend/src/pages/secret-manager/integrations/AzureKeyVaultOauthCallbackPage/AzureKeyVaultOauthCallback.tsx b/frontend/src/pages/secret-manager/integrations/AzureKeyVaultOauthCallbackPage/AzureKeyVaultOauthCallback.tsx index ef98d1cba..90a93edce 100644 --- a/frontend/src/pages/secret-manager/integrations/AzureKeyVaultOauthCallbackPage/AzureKeyVaultOauthCallback.tsx +++ b/frontend/src/pages/secret-manager/integrations/AzureKeyVaultOauthCallbackPage/AzureKeyVaultOauthCallback.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useAuthorizeIntegration } from "@app/hooks/api"; export const AzureKeyVaultOauthCallbackPage = () => { @@ -12,7 +12,7 @@ export const AzureKeyVaultOauthCallbackPage = () => { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.AzureKeyVaultOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -22,7 +22,7 @@ export const AzureKeyVaultOauthCallbackPage = () => { localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, integration: "azure-key-vault" }); @@ -30,7 +30,7 @@ export const AzureKeyVaultOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/azure-key-vault/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/BitbucketConfigurePage/BitbucketConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/BitbucketConfigurePage/BitbucketConfigurePage.tsx index 10dafdb76..022a8e8d7 100644 --- a/frontend/src/pages/secret-manager/integrations/BitbucketConfigurePage/BitbucketConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/BitbucketConfigurePage/BitbucketConfigurePage.tsx @@ -16,7 +16,7 @@ import { Spinner } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration, useGetIntegrationAuthApps, @@ -96,7 +96,7 @@ export const BitbucketConfigurePage = () => { from: ROUTE_PATHS.SecretManager.Integratons.BitbucketConfigurePage.id, select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: bitbucketWorkspaces, isPending: isBitbucketWorkspacesLoading } = useGetIntegrationAuthBitbucketWorkspaces((integrationAuthId as string) ?? ""); @@ -150,7 +150,7 @@ export const BitbucketConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -171,18 +171,18 @@ export const BitbucketConfigurePage = () => { bitbucketRepo || !bitbucketRepos || !bitbucketWorkspaces || - !currentWorkspace + !currentProject ) return; reset({ targetRepo: bitbucketRepos[0], targetWorkspace: bitbucketWorkspaces[0], - sourceEnvironment: currentWorkspace.environments[0], + sourceEnvironment: currentProject.environments[0], secretPath: "/", scope: ScopeOptions[0] }); - }, [bitbucketWorkspaces, bitbucketRepos, currentWorkspace]); + }, [bitbucketWorkspaces, bitbucketRepos, currentProject]); if (isBitbucketWorkspacesLoading || isBitbucketReposLoading) return ( @@ -217,9 +217,9 @@ export const BitbucketConfigurePage = () => { value={value} getOptionLabel={(option) => option.name} onChange={onChange} - options={currentWorkspace?.environments} + options={currentProject?.environments} placeholder="Select a project environment" - isDisabled={!currentWorkspace?.environments.length} + isDisabled={!currentProject?.environments.length} /> )} diff --git a/frontend/src/pages/secret-manager/integrations/BitbucketOauthCallbackPage/BitbucketOauthCallbackPage.tsx b/frontend/src/pages/secret-manager/integrations/BitbucketOauthCallbackPage/BitbucketOauthCallbackPage.tsx index 1e3d302f2..8b23f46ab 100644 --- a/frontend/src/pages/secret-manager/integrations/BitbucketOauthCallbackPage/BitbucketOauthCallbackPage.tsx +++ b/frontend/src/pages/secret-manager/integrations/BitbucketOauthCallbackPage/BitbucketOauthCallbackPage.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useAuthorizeIntegration } from "@app/hooks/api"; export const BitbucketOauthCallbackPage = () => { @@ -11,7 +11,7 @@ export const BitbucketOauthCallbackPage = () => { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.BitbucketOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -21,7 +21,7 @@ export const BitbucketOauthCallbackPage = () => { localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, integration: "bitbucket" }); @@ -29,7 +29,7 @@ export const BitbucketOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/bitbucket/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/ChecklyAuthorizePage/ChecklyAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/ChecklyAuthorizePage/ChecklyAuthorizePage.tsx index 5dd711fc0..43521fd2e 100644 --- a/frontend/src/pages/secret-manager/integrations/ChecklyAuthorizePage/ChecklyAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/ChecklyAuthorizePage/ChecklyAuthorizePage.tsx @@ -5,13 +5,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const ChecklyAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [accessToken, setAccessToken] = useState(""); const [accessTokenErrorText, setAccessTokenErrorText] = useState(""); @@ -28,7 +28,7 @@ export const ChecklyAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "checkly", accessToken }); @@ -38,7 +38,7 @@ export const ChecklyAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/checkly/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/ChecklyConfigurePage/ChecklyConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/ChecklyConfigurePage/ChecklyConfigurePage.tsx index 2e02f7cf2..e09a1361a 100644 --- a/frontend/src/pages/secret-manager/integrations/ChecklyConfigurePage/ChecklyConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/ChecklyConfigurePage/ChecklyConfigurePage.tsx @@ -19,14 +19,14 @@ import { Tabs } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, useGetIntegrationAuthById, useGetIntegrationAuthChecklyGroups } from "@app/hooks/api/integrationAuth"; -import { useGetWorkspaceById } from "@app/hooks/api/workspace"; +import { useGetWorkspaceById } from "@app/hooks/api/projects"; import { IntegrationsListPageTabs } from "@app/types/integrations"; enum TabSections { @@ -42,7 +42,7 @@ export const ChecklyConfigurePage = () => { from: ROUTE_PATHS.SecretManager.Integratons.ChecklyConfigurePage.id, select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -53,7 +53,7 @@ export const ChecklyConfigurePage = () => { const [isLoading, setIsLoading] = useState(false); - const { data: workspace } = useGetWorkspaceById(currentWorkspace.id); + const { data: workspace } = useGetWorkspaceById(currentProject.id); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuthApps, isPending: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ @@ -115,7 +115,7 @@ export const ChecklyConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations diff --git a/frontend/src/pages/secret-manager/integrations/CircleCIAuthorizePage/CircleCIAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/CircleCIAuthorizePage/CircleCIAuthorizePage.tsx index e64227fc3..088c22e1d 100644 --- a/frontend/src/pages/secret-manager/integrations/CircleCIAuthorizePage/CircleCIAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/CircleCIAuthorizePage/CircleCIAuthorizePage.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const CircleCIAuthorizePage = () => { @@ -15,7 +15,7 @@ export const CircleCIAuthorizePage = () => { const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [isLoading, setIsLoading] = useState(false); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const handleButtonClick = async () => { try { @@ -28,7 +28,7 @@ export const CircleCIAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "circleci", accessToken: apiKey }); @@ -38,7 +38,7 @@ export const CircleCIAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/circleci/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/CircleCIConfigurePage/CircleCIConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/CircleCIConfigurePage/CircleCIConfigurePage.tsx index f03f35af8..36777af29 100644 --- a/frontend/src/pages/secret-manager/integrations/CircleCIConfigurePage/CircleCIConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/CircleCIConfigurePage/CircleCIConfigurePage.tsx @@ -18,7 +18,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration, useGetIntegrationAuthCircleCIOrganizations } from "@app/hooks/api"; import { CircleCiScope } from "@app/hooks/api/integrationAuth/types"; import { IntegrationsListPageTabs } from "@app/types/integrations"; @@ -45,7 +45,7 @@ type TFormData = z.infer; export const CircleCIConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync, isPending: isCreatingIntegration } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.CircleConfigurePage.id, @@ -56,7 +56,7 @@ export const CircleCIConfigurePage = () => { resolver: zodResolver(formSchema), defaultValues: { secretPath: "/", - sourceEnvironment: currentWorkspace?.environments[0], + sourceEnvironment: currentProject?.environments[0], scope: CircleCiScope.Project } }); @@ -105,7 +105,7 @@ export const CircleCIConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -179,9 +179,9 @@ export const CircleCIConfigurePage = () => { value={value} getOptionLabel={(option) => option.name} onChange={onChange} - options={currentWorkspace?.environments} + options={currentProject?.environments} placeholder="Select a project environment" - isDisabled={!currentWorkspace?.environments.length} + isDisabled={!currentProject?.environments.length} /> )} diff --git a/frontend/src/pages/secret-manager/integrations/Cloud66AuthorizePage/Cloud66AuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/Cloud66AuthorizePage/Cloud66AuthorizePage.tsx index 8fc9dd5ca..1a464cadc 100644 --- a/frontend/src/pages/secret-manager/integrations/Cloud66AuthorizePage/Cloud66AuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/Cloud66AuthorizePage/Cloud66AuthorizePage.tsx @@ -2,14 +2,14 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const Cloud66AuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); @@ -26,7 +26,7 @@ export const Cloud66AuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "cloud-66", accessToken: apiKey }); @@ -36,7 +36,7 @@ export const Cloud66AuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/cloud-66/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/Cloud66ConfigurePage/Cloud66ConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/Cloud66ConfigurePage/Cloud66ConfigurePage.tsx index 6de5e3bc3..68535d70e 100644 --- a/frontend/src/pages/secret-manager/integrations/Cloud66ConfigurePage/Cloud66ConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/Cloud66ConfigurePage/Cloud66ConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -28,7 +28,7 @@ export const Cloud66ConfigurePage = () => { select: (el) => el.integrationAuthId }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuthApps } = useGetIntegrationAuthApps({ integrationAuthId: (integrationAuthId as string) ?? "" @@ -40,10 +40,10 @@ export const Cloud66ConfigurePage = () => { const [isLoading, setIsLoading] = useState(false); useEffect(() => { - if (currentWorkspace) { - setSelectedSourceEnvironment(currentWorkspace.environments[0].slug); + if (currentProject) { + setSelectedSourceEnvironment(currentProject.environments[0].slug); } - }, [currentWorkspace]); + }, [currentProject]); useEffect(() => { if (integrationAuthApps) { @@ -77,7 +77,7 @@ export const Cloud66ConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -98,7 +98,7 @@ export const Cloud66ConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -14,7 +14,7 @@ export const CloudflarePagesAuthorizePage = () => { const [accountIdErrorText, setAccountIdErrorText] = useState(""); const [isLoading, setIsLoading] = useState(false); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); const handleButtonClick = async () => { @@ -30,7 +30,7 @@ export const CloudflarePagesAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "cloudflare-pages", accessId: accountId, accessToken: accessKey @@ -43,7 +43,7 @@ export const CloudflarePagesAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/cloudflare-pages/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/CloudflarePagesConfigurePage/CloudflarePagesConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/CloudflarePagesConfigurePage/CloudflarePagesConfigurePage.tsx index 1ff6e75d5..69225d9ae 100644 --- a/frontend/src/pages/secret-manager/integrations/CloudflarePagesConfigurePage/CloudflarePagesConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/CloudflarePagesConfigurePage/CloudflarePagesConfigurePage.tsx @@ -14,7 +14,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration, useGetWorkspaceById } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -31,7 +31,7 @@ export const CloudflarePagesConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.CloudflarePagesConfigurePage.id, @@ -39,7 +39,7 @@ export const CloudflarePagesConfigurePage = () => { }); const [secretPath, setSecretPath] = useState("/"); - const { data: workspace } = useGetWorkspaceById(currentWorkspace.id); + const { data: workspace } = useGetWorkspaceById(currentProject.id); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuthApps } = useGetIntegrationAuthApps({ integrationAuthId: (integrationAuthId as string) ?? "" @@ -96,7 +96,7 @@ export const CloudflarePagesConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations diff --git a/frontend/src/pages/secret-manager/integrations/CloudflareWorkersAuthorizePage/CloudflareWorkersAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/CloudflareWorkersAuthorizePage/CloudflareWorkersAuthorizePage.tsx index e2829c76a..dd0b16a6b 100644 --- a/frontend/src/pages/secret-manager/integrations/CloudflareWorkersAuthorizePage/CloudflareWorkersAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/CloudflareWorkersAuthorizePage/CloudflareWorkersAuthorizePage.tsx @@ -2,13 +2,13 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const CloudflareWorkersAuthorizePage = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync } = useSaveIntegrationAccessToken(); const [accessKey, setAccessKey] = useState(""); @@ -30,7 +30,7 @@ export const CloudflareWorkersAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "cloudflare-workers", accessId: accountId, accessToken: accessKey @@ -43,7 +43,7 @@ export const CloudflareWorkersAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/cloudflare-workers/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/CloudflareWorkersConfigurePage/CloudflareWorkersConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/CloudflareWorkersConfigurePage/CloudflareWorkersConfigurePage.tsx index bfc4b766a..a5d28bb95 100644 --- a/frontend/src/pages/secret-manager/integrations/CloudflareWorkersConfigurePage/CloudflareWorkersConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/CloudflareWorkersConfigurePage/CloudflareWorkersConfigurePage.tsx @@ -6,7 +6,7 @@ import { createNotification } from "@app/components/notifications"; import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -17,7 +17,7 @@ import { IntegrationsListPageTabs } from "@app/types/integrations"; export const CloudflareWorkersConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.CloudflareWorkersConfigurePage.id, @@ -29,7 +29,7 @@ export const CloudflareWorkersConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); @@ -69,7 +69,7 @@ export const CloudflareWorkersConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -107,7 +107,7 @@ export const CloudflareWorkersConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -12,7 +12,7 @@ export const CodefreshAuthorizePage = () => { const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [isLoading, setIsLoading] = useState(false); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const handleButtonClick = async () => { try { @@ -25,7 +25,7 @@ export const CodefreshAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "codefresh", accessToken: apiKey }); @@ -35,7 +35,7 @@ export const CodefreshAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/codefresh/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/CodefreshConfigurePage/CodefreshConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/CodefreshConfigurePage/CodefreshConfigurePage.tsx index e99ad4ea8..80a54b621 100644 --- a/frontend/src/pages/secret-manager/integrations/CodefreshConfigurePage/CodefreshConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/CodefreshConfigurePage/CodefreshConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -23,7 +23,7 @@ export const CodefreshConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.CodefreshConfigurePage.id, select: (el) => el.integrationAuthId @@ -35,7 +35,7 @@ export const CodefreshConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetApp, setTargetApp] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -73,7 +73,7 @@ export const CodefreshConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -94,7 +94,7 @@ export const CodefreshConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -17,7 +17,7 @@ export const DatabricksAuthorizePage = () => { const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [instanceURLErrorText, setInstanceURLErrorText] = useState(""); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const handleButtonClick = async () => { try { @@ -33,7 +33,7 @@ export const DatabricksAuthorizePage = () => { } const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "databricks", url: instanceURL.replace(/\/$/, ""), accessToken: apiKey @@ -42,7 +42,7 @@ export const DatabricksAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/databricks/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/DatabricksConfigurePage/DatabricksConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/DatabricksConfigurePage/DatabricksConfigurePage.tsx index 0f3d09728..a140a0339 100644 --- a/frontend/src/pages/secret-manager/integrations/DatabricksConfigurePage/DatabricksConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/DatabricksConfigurePage/DatabricksConfigurePage.tsx @@ -20,7 +20,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -32,7 +32,7 @@ export const DatabricksConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync, isPending } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.DatabricksConfigurePage.id, @@ -49,7 +49,7 @@ export const DatabricksConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetScope, setTargetScope] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -89,7 +89,7 @@ export const DatabricksConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -143,7 +143,7 @@ export const DatabricksConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -12,7 +12,7 @@ export const DigitalOceanAppPlatformAuthorizePage = () => { const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [isLoading, setIsLoading] = useState(false); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const handleButtonClick = async () => { try { @@ -25,7 +25,7 @@ export const DigitalOceanAppPlatformAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "digital-ocean-app-platform", accessToken: apiKey }); @@ -35,7 +35,7 @@ export const DigitalOceanAppPlatformAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/digital-ocean-app-platform/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/DigitalOceanAppPlatformConfigurePage/DigitalOceanAppPlatformConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/DigitalOceanAppPlatformConfigurePage/DigitalOceanAppPlatformConfigurePage.tsx index e88d98976..2c6f08348 100644 --- a/frontend/src/pages/secret-manager/integrations/DigitalOceanAppPlatformConfigurePage/DigitalOceanAppPlatformConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/DigitalOceanAppPlatformConfigurePage/DigitalOceanAppPlatformConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -23,7 +23,7 @@ export const DigitalOceanAppPlatformConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.DigitalOceanAppPlatformConfigurePage.id, @@ -36,7 +36,7 @@ export const DigitalOceanAppPlatformConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetApp, setTargetApp] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -74,7 +74,7 @@ export const DigitalOceanAppPlatformConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -95,7 +95,7 @@ export const DigitalOceanAppPlatformConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( ; export const FlyioAuthorizePage = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit } = useForm({ resolver: zodResolver(schema), @@ -37,7 +37,7 @@ export const FlyioAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "flyio", accessToken }); @@ -46,7 +46,7 @@ export const FlyioAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/flyio/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/FlyioConfigurePage/FlyioConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/FlyioConfigurePage/FlyioConfigurePage.tsx index 0beb61bdf..c034ce3f1 100644 --- a/frontend/src/pages/secret-manager/integrations/FlyioConfigurePage/FlyioConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/FlyioConfigurePage/FlyioConfigurePage.tsx @@ -21,7 +21,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -34,7 +34,7 @@ export const FlyioConfigurePage = () => { const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.FlyioConfigurePage.id, @@ -50,7 +50,7 @@ export const FlyioConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); @@ -88,7 +88,7 @@ export const FlyioConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -144,7 +144,7 @@ export const FlyioConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { }); const { data: cloudIntegrations } = useGetCloudIntegrations(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync } = useSaveIntegrationAccessToken(); @@ -47,7 +47,7 @@ export const GcpSecretManagerAuthorizePage = () => { const state = crypto.randomBytes(16).toString("hex"); localStorage.setItem("latestCSRFToken", state); - localStorageService.setIntegrationProjectId(currentWorkspace.id); + localStorageService.setIntegrationProjectId(currentProject.id); if (!integrationOption.clientId) { createIntegrationMissingEnvVarsNotification(integrationOption.slug); @@ -63,7 +63,7 @@ export const GcpSecretManagerAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "gcp-secret-manager", refreshToken: accessToken }); @@ -72,7 +72,7 @@ export const GcpSecretManagerAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/gcp-secret-manager/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/GcpSecretManagerConfigurePage/GcpSecretManagerConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/GcpSecretManagerConfigurePage/GcpSecretManagerConfigurePage.tsx index c4f8403bd..85af1961f 100644 --- a/frontend/src/pages/secret-manager/integrations/GcpSecretManagerConfigurePage/GcpSecretManagerConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/GcpSecretManagerConfigurePage/GcpSecretManagerConfigurePage.tsx @@ -26,7 +26,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useCreateIntegration } from "@app/hooks/api"; import { @@ -59,7 +59,7 @@ export const GcpSecretManagerConfigurePage = () => { "confirmIntegration" ] as const); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, setValue, watch } = useForm({ resolver: zodResolver(schema), defaultValues: { @@ -69,7 +69,7 @@ export const GcpSecretManagerConfigurePage = () => { shouldLabel: false, labelName: "managed-by", labelValue: "infisical", - selectedSourceEnvironment: currentWorkspace.environments[0].slug + selectedSourceEnvironment: currentProject.environments[0].slug } }); @@ -153,7 +153,7 @@ export const GcpSecretManagerConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -241,7 +241,7 @@ export const GcpSecretManagerConfigurePage = () => { onValueChange={(e) => onChange(e)} className="w-full" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -12,7 +12,7 @@ export const GcpSecretManagerOauthCallbackPage = () => { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.GcpSecretManagerOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -22,7 +22,7 @@ export const GcpSecretManagerOauthCallbackPage = () => { if (state !== localStorage.getItem("latestCSRFToken")) return; localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, integration: "gcp-secret-manager" }); @@ -30,7 +30,7 @@ export const GcpSecretManagerOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/gcp-secret-manager/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/GithubAuthorizePage/GithubAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/GithubAuthorizePage/GithubAuthorizePage.tsx index 623c5762c..e4fe73feb 100644 --- a/frontend/src/pages/secret-manager/integrations/GithubAuthorizePage/GithubAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/GithubAuthorizePage/GithubAuthorizePage.tsx @@ -15,7 +15,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { localStorageService } from "@app/helpers/localStorage"; import { useGetCloudIntegrations } from "@app/hooks/api"; @@ -31,7 +31,7 @@ export const GithubAuthorizePage = () => { const { data: cloudIntegrations } = useGetCloudIntegrations(); const githubIntegration = cloudIntegrations?.find((integration) => integration.slug === "github"); const [selectedAuthMethod, setSelectedAuthMethod] = useState(AuthMethod.APP); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); return (
@@ -84,7 +84,7 @@ export const GithubAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/select-integration-auth", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationSlug: "github" @@ -102,7 +102,7 @@ export const GithubAuthorizePage = () => { const state = crypto.randomBytes(16).toString("hex"); localStorage.setItem("latestCSRFToken", state); - localStorageService.setIntegrationProjectId(currentWorkspace.id); + localStorageService.setIntegrationProjectId(currentProject.id); window.location.assign( `https://github.com/login/oauth/authorize?client_id=${githubIntegration?.clientId}&response_type=code&scope=repo,admin:org&redirect_uri=${window.location.origin}/integrations/github/oauth2/callback&state=${state}` ); diff --git a/frontend/src/pages/secret-manager/integrations/GithubConfigurePage/GithubConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/GithubConfigurePage/GithubConfigurePage.tsx index aa71c793e..7dad0d29a 100644 --- a/frontend/src/pages/secret-manager/integrations/GithubConfigurePage/GithubConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/GithubConfigurePage/GithubConfigurePage.tsx @@ -37,7 +37,7 @@ import { Tabs } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration, useGetIntegrationAuthApps, @@ -142,7 +142,7 @@ export const GithubConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.GithubConfigurePage.id, select: (el) => el.integrationAuthId @@ -166,7 +166,7 @@ export const GithubConfigurePage = () => { repoIds: [], visibility: "all", shouldEnableDelete: false, - selectedSourceEnvironment: currentWorkspace.environments[0].slug + selectedSourceEnvironment: currentProject.environments[0].slug } }); @@ -269,7 +269,7 @@ export const GithubConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -367,7 +367,7 @@ export const GithubConfigurePage = () => { onValueChange={onChange} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -16,7 +16,7 @@ export const GithubOauthCallbackPage = () => { } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.GithubOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -29,7 +29,7 @@ export const GithubOauthCallbackPage = () => { localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, installationId, integration: "github" @@ -38,7 +38,7 @@ export const GithubOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/github/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/GitlabAuthorizePage/GitlabAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/GitlabAuthorizePage/GitlabAuthorizePage.tsx index 2ce82d97c..cf77aa312 100644 --- a/frontend/src/pages/secret-manager/integrations/GitlabAuthorizePage/GitlabAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/GitlabAuthorizePage/GitlabAuthorizePage.tsx @@ -8,7 +8,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { localStorageService } from "@app/helpers/localStorage"; import { useGetCloudIntegrations } from "@app/hooks/api"; @@ -29,7 +29,7 @@ export const GitlabAuthorizePage = () => { }); const { data: cloudIntegrations } = useGetCloudIntegrations(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const onFormSubmit = ({ gitLabURL }: FormData) => { if (!cloudIntegrations) return; @@ -49,12 +49,12 @@ export const GitlabAuthorizePage = () => { const csrfToken = crypto.randomBytes(16).toString("hex"); localStorage.setItem("latestCSRFToken", csrfToken); - localStorageService.setIntegrationProjectId(currentWorkspace.id); + localStorageService.setIntegrationProjectId(currentProject.id); const state = `${csrfToken}|${ (gitLabURL as string).trim() === "" ? "" : (gitLabURL as string).trim() }`; - localStorageService.setIntegrationProjectId(currentWorkspace.id); + localStorageService.setIntegrationProjectId(currentProject.id); const link = `${baseURL}/oauth/authorize?client_id=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`; window.location.assign(link); diff --git a/frontend/src/pages/secret-manager/integrations/GitlabConfigurePage/GitlabConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/GitlabConfigurePage/GitlabConfigurePage.tsx index 6fb388b71..13d2081ad 100644 --- a/frontend/src/pages/secret-manager/integrations/GitlabConfigurePage/GitlabConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/GitlabConfigurePage/GitlabConfigurePage.tsx @@ -26,7 +26,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { usePopUp } from "@app/hooks"; import { useCreateIntegration } from "@app/hooks/api"; import { @@ -76,7 +76,7 @@ export const GitlabConfigurePage = () => { const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ "confirmIntegration" ] as const); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, setValue, watch } = useForm({ resolver: zodResolver(schema), @@ -85,7 +85,7 @@ export const GitlabConfigurePage = () => { secretPath: "/", secretPrefix: "", secretSuffix: "", - selectedSourceEnvironment: currentWorkspace.environments[0].slug, + selectedSourceEnvironment: currentProject.environments[0].slug, initialSyncBehavior: IntegrationSyncBehavior.PREFER_SOURCE } }); @@ -177,7 +177,7 @@ export const GitlabConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -267,7 +267,7 @@ export const GitlabConfigurePage = () => { onValueChange={(e) => onChange(e)} className="w-full" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.GitlabOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -65,7 +65,7 @@ export const GitLabOAuthCallbackPage = () => { }); } else { appConnection = await createAppConnection({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, ...connectionData }); } @@ -87,7 +87,7 @@ export const GitLabOAuthCallbackPage = () => { }); } })(); - }, [code, state, navigate, createAppConnection, updateAppConnection, currentWorkspace.id]); + }, [code, state, navigate, createAppConnection, updateAppConnection, currentProject.id]); return (
diff --git a/frontend/src/pages/secret-manager/integrations/HashicorpVaultAuthorizePage/HashicorpVaultAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/HashicorpVaultAuthorizePage/HashicorpVaultAuthorizePage.tsx index ae200968a..8a8cbbc4c 100644 --- a/frontend/src/pages/secret-manager/integrations/HashicorpVaultAuthorizePage/HashicorpVaultAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/HashicorpVaultAuthorizePage/HashicorpVaultAuthorizePage.tsx @@ -9,7 +9,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, Card, CardBody, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; const formSchema = z.object({ @@ -25,7 +25,7 @@ export const HashicorpVaultAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, @@ -43,7 +43,7 @@ export const HashicorpVaultAuthorizePage = () => { const handleFormSubmit = async (formData: TForm) => { try { const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "hashicorp-vault", accessId: formData.vaultRoleID, accessToken: formData.vaultSecretID, @@ -53,7 +53,7 @@ export const HashicorpVaultAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/hashicorp-vault/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/HashicorpVaultConfigurePage/HashicorpVaultConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/HashicorpVaultConfigurePage/HashicorpVaultConfigurePage.tsx index af9af585e..48b31dd80 100644 --- a/frontend/src/pages/secret-manager/integrations/HashicorpVaultConfigurePage/HashicorpVaultConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/HashicorpVaultConfigurePage/HashicorpVaultConfigurePage.tsx @@ -25,7 +25,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { isValidPath } from "@app/helpers/string"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; @@ -61,7 +61,7 @@ export const HashicorpVaultConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.HashicorpVaultConfigurePage.id, select: (el) => el.integrationAuthId @@ -72,8 +72,8 @@ export const HashicorpVaultConfigurePage = () => { ); const formSchema = useMemo(() => { - return generateFormSchema(currentWorkspace?.environments.map((env) => env.slug) ?? []); - }, [currentWorkspace?.environments]); + return generateFormSchema(currentProject?.environments.map((env) => env.slug) ?? []); + }, [currentProject?.environments]); const { control, @@ -103,7 +103,7 @@ export const HashicorpVaultConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -177,7 +177,7 @@ export const HashicorpVaultConfigurePage = () => { onValueChange={field.onChange} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const [isLoading, setIsLoading] = useState(false); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit } = useForm({ resolver: zodResolver(schema), defaultValues: { @@ -36,7 +36,7 @@ export const HasuraCloudAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "hasura-cloud", accessToken }); @@ -45,7 +45,7 @@ export const HasuraCloudAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/hasura-cloud/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/HasuraCloudConfigurePage/HasuraCloudConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/HasuraCloudConfigurePage/HasuraCloudConfigurePage.tsx index a42451e8e..cfcba8058 100644 --- a/frontend/src/pages/secret-manager/integrations/HasuraCloudConfigurePage/HasuraCloudConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/HasuraCloudConfigurePage/HasuraCloudConfigurePage.tsx @@ -9,7 +9,7 @@ import { z } from "zod"; import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -38,7 +38,7 @@ export const HasuraCloudConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.HasuraCloudConfigurePage.id, select: (el) => el.integrationAuthId @@ -72,7 +72,7 @@ export const HasuraCloudConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -137,7 +137,7 @@ export const HasuraCloudConfigurePage = () => { field.onChange(val); }} > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( ; export const HerokuConfigurePage = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, setValue, watch } = useForm({ resolver: zodResolver(schema), defaultValues: { secretPath: "/", initialSyncBehavior: IntegrationSyncBehavior.PREFER_SOURCE, - selectedSourceEnvironment: currentWorkspace.environments[0].slug + selectedSourceEnvironment: currentProject.environments[0].slug } }); @@ -100,7 +100,7 @@ export const HerokuConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -158,7 +158,7 @@ export const HerokuConfigurePage = () => { onValueChange={(e) => onChange(e)} className="w-full" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { from: ROUTE_PATHS.SecretManager.Integratons.HerokuOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -67,7 +67,7 @@ export const HerokuOAuthCallbackPage = () => { }); } else { appConnection = await createAppConnection({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, ...connectionData }); } @@ -88,7 +88,7 @@ export const HerokuOAuthCallbackPage = () => { }); } })(); - }, [code, state, navigate, createAppConnection, updateAppConnection, currentWorkspace.id]); + }, [code, state, navigate, createAppConnection, updateAppConnection, currentProject.id]); return (
diff --git a/frontend/src/pages/secret-manager/integrations/LaravelForgeAuthorizePage/LaravelForgeAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/LaravelForgeAuthorizePage/LaravelForgeAuthorizePage.tsx index d67a6ce1d..c607472c7 100644 --- a/frontend/src/pages/secret-manager/integrations/LaravelForgeAuthorizePage/LaravelForgeAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/LaravelForgeAuthorizePage/LaravelForgeAuthorizePage.tsx @@ -2,13 +2,13 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const LaravelForgeAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [serverId, setServerId] = useState(""); @@ -33,7 +33,7 @@ export const LaravelForgeAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "laravel-forge", accessId: serverId, accessToken: apiKey @@ -44,7 +44,7 @@ export const LaravelForgeAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/laravel-forge/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/LaravelForgeConfigurePage/LaravelForgeConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/LaravelForgeConfigurePage/LaravelForgeConfigurePage.tsx index 91963e749..55a5ac360 100644 --- a/frontend/src/pages/secret-manager/integrations/LaravelForgeConfigurePage/LaravelForgeConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/LaravelForgeConfigurePage/LaravelForgeConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -23,7 +23,7 @@ export const LaravelForgeConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.LaravelForgeConfigurePage.id, select: (el) => el.integrationAuthId @@ -35,7 +35,7 @@ export const LaravelForgeConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetApp, setTargetApp] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -74,7 +74,7 @@ export const LaravelForgeConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -95,7 +95,7 @@ export const LaravelForgeConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.NetlifyConfigurePage.id, select: (el) => el.integrationAuthId @@ -42,7 +42,7 @@ export const NetlifyConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetApp, setTargetApp] = useState(""); const [targetEnvironment, setTargetEnvironment] = useState(netlifyEnvironments[0].slug); @@ -81,7 +81,7 @@ export const NetlifyConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -106,7 +106,7 @@ export const NetlifyConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -12,7 +12,7 @@ export const NetlifyOauthCallbackPage = () => { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.NetlifyOuathCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -22,7 +22,7 @@ export const NetlifyOauthCallbackPage = () => { localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, integration: "netlify" }); @@ -30,7 +30,7 @@ export const NetlifyOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/netlify/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/NorthflankAuthorizePage/NorthflankAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/NorthflankAuthorizePage/NorthflankAuthorizePage.tsx index b203a02dc..005a4914e 100644 --- a/frontend/src/pages/secret-manager/integrations/NorthflankAuthorizePage/NorthflankAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/NorthflankAuthorizePage/NorthflankAuthorizePage.tsx @@ -2,13 +2,13 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const NorthflankAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); @@ -25,7 +25,7 @@ export const NorthflankAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "northflank", accessToken: apiKey }); @@ -35,7 +35,7 @@ export const NorthflankAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/northflank/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/NorthflankConfigurePage/NorthflankConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/NorthflankConfigurePage/NorthflankConfigurePage.tsx index 7f01c32ee..9ff1e18c8 100644 --- a/frontend/src/pages/secret-manager/integrations/NorthflankConfigurePage/NorthflankConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/NorthflankConfigurePage/NorthflankConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -24,9 +24,9 @@ export const NorthflankConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); const [targetAppId, setTargetAppId] = useState(""); @@ -95,7 +95,7 @@ export const NorthflankConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -116,7 +116,7 @@ export const NorthflankConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( ; export const OctopusDeployAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync, isPending } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit } = useForm({ resolver: zodResolver(formSchema) @@ -31,7 +31,7 @@ export const OctopusDeployAuthorizePage = () => { const onSubmit = async ({ instanceUrl, apiKey }: TForm) => { try { const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "octopus-deploy", url: removeTrailingSlash(instanceUrl), accessToken: apiKey @@ -40,7 +40,7 @@ export const OctopusDeployAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/octopus-deploy/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/OctopusDeployConfigurePage/OctopusDeployConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/OctopusDeployConfigurePage/OctopusDeployConfigurePage.tsx index 458c4a997..bddd884f4 100644 --- a/frontend/src/pages/secret-manager/integrations/OctopusDeployConfigurePage/OctopusDeployConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/OctopusDeployConfigurePage/OctopusDeployConfigurePage.tsx @@ -16,7 +16,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration, useGetIntegrationAuthApps } from "@app/hooks/api"; import { useGetIntegrationAuthOctopusDeployScopeValues, @@ -56,7 +56,7 @@ export const OctopusDeployConfigurePage = () => { } }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.OctopusDeployCloudConfigurePage.id, select: (el) => el.integrationAuthId @@ -137,7 +137,7 @@ export const OctopusDeployConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -153,16 +153,16 @@ export const OctopusDeployConfigurePage = () => { }; useEffect(() => { - if (!octopusDeployResources || !octopusDeploySpaces || !currentWorkspace) return; + if (!octopusDeployResources || !octopusDeploySpaces || !currentProject) return; reset({ targetResource: octopusDeployResources[0], targetSpace: octopusDeploySpaces.find((space) => space.IsDefault), - sourceEnvironment: currentWorkspace.environments[0], + sourceEnvironment: currentProject.environments[0], secretPath: "/", scope: OctopusDeployScope.Project }); - }, [octopusDeploySpaces, octopusDeployResources, currentWorkspace]); + }, [octopusDeploySpaces, octopusDeployResources, currentProject]); if (isLoadingOctopusDeploySpaces || isOctopusDeployResourcesLoading) return ( @@ -196,9 +196,9 @@ export const OctopusDeployConfigurePage = () => { value={value} getOptionLabel={(option) => option.name} onChange={onChange} - options={currentWorkspace?.environments} + options={currentProject?.environments} placeholder="Select a project environment" - isDisabled={!currentWorkspace?.environments.length} + isDisabled={!currentProject?.environments.length} /> )} diff --git a/frontend/src/pages/secret-manager/integrations/QoveryAuthorizePage/QoveryAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/QoveryAuthorizePage/QoveryAuthorizePage.tsx index 607b1962b..369046df9 100644 --- a/frontend/src/pages/secret-manager/integrations/QoveryAuthorizePage/QoveryAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/QoveryAuthorizePage/QoveryAuthorizePage.tsx @@ -5,12 +5,12 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const QoveryAuthorizePage = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync } = useSaveIntegrationAccessToken(); const [accessToken, setAccessToken] = useState(""); @@ -28,7 +28,7 @@ export const QoveryAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "qovery", accessToken }); @@ -38,7 +38,7 @@ export const QoveryAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/qovery/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/QoveryConfigurePage/QoveryConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/QoveryConfigurePage/QoveryConfigurePage.tsx index bc0f24c90..977f4fdd1 100644 --- a/frontend/src/pages/secret-manager/integrations/QoveryConfigurePage/QoveryConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/QoveryConfigurePage/QoveryConfigurePage.tsx @@ -19,7 +19,7 @@ import { Tabs } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; import { @@ -55,7 +55,7 @@ enum TabSections { export const QoveryConfigurePage = () => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync } = useCreateIntegration(); const integrationAuthId = useSearch({ @@ -67,7 +67,7 @@ export const QoveryConfigurePage = () => { const [scope, setScope] = useState("application"); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); @@ -178,7 +178,7 @@ export const QoveryConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -241,7 +241,7 @@ export const QoveryConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); @@ -25,7 +25,7 @@ export const RailwayAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "railway", accessToken: apiKey }); @@ -35,7 +35,7 @@ export const RailwayAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/railway/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/RailwayConfigurePage/RailwayConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/RailwayConfigurePage/RailwayConfigurePage.tsx index 835e59277..1d24f7ce7 100644 --- a/frontend/src/pages/secret-manager/integrations/RailwayConfigurePage/RailwayConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/RailwayConfigurePage/RailwayConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -25,13 +25,13 @@ export const RailwayConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [targetAppId, setTargetAppId] = useState(""); const [targetEnvironmentId, setTargetEnvironmentId] = useState(""); const [targetServiceId, setTargetServiceId] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); const [isLoading, setIsLoading] = useState(false); @@ -110,7 +110,7 @@ export const RailwayConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -139,7 +139,7 @@ export const RailwayConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); @@ -28,7 +28,7 @@ export const RenderAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "render", accessToken: apiKey }); @@ -38,7 +38,7 @@ export const RenderAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/render/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/RenderConfigurePage/RenderConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/RenderConfigurePage/RenderConfigurePage.tsx index 3d156cdac..4a2ef30d1 100644 --- a/frontend/src/pages/secret-manager/integrations/RenderConfigurePage/RenderConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/RenderConfigurePage/RenderConfigurePage.tsx @@ -23,7 +23,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -44,13 +44,13 @@ export const RenderConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit, setValue, watch } = useForm({ resolver: zodResolver(schema), defaultValues: { secretPath: "/", shouldAutoRedeploy: false, - selectedSourceEnvironment: currentWorkspace.environments[0].slug + selectedSourceEnvironment: currentProject.environments[0].slug } }); @@ -106,7 +106,7 @@ export const RenderConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -167,7 +167,7 @@ export const RenderConfigurePage = () => { onValueChange={(e) => onChange(e)} className="w-full" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const [isLoading, setIsLoading] = useState(false); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { control, handleSubmit } = useForm({ resolver: zodResolver(schema), @@ -40,7 +40,7 @@ export const RundeckAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "rundeck", accessToken: authToken, url: rundeckURL.trim() @@ -50,7 +50,7 @@ export const RundeckAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/rundeck/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/RundeckConfigurePage/RundeckConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/RundeckConfigurePage/RundeckConfigurePage.tsx index 7c8dada9f..555a5cc5c 100644 --- a/frontend/src/pages/secret-manager/integrations/RundeckConfigurePage/RundeckConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/RundeckConfigurePage/RundeckConfigurePage.tsx @@ -17,7 +17,7 @@ import { } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthById } from "@app/hooks/api/integrationAuth"; import { IntegrationsListPageTabs } from "@app/types/integrations"; @@ -44,7 +44,7 @@ export const RundeckConfigurePage = () => { }); const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.RundeckConfigurePage.id, @@ -73,7 +73,7 @@ export const RundeckConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -138,7 +138,7 @@ export const RundeckConfigurePage = () => { field.onChange(val); }} > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { isError={Boolean(error)} > { const navigate = useNavigate(); const { data: cloudIntegrations } = useGetCloudIntegrations(); const { currentOrg } = useOrganization(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const orgId = currentOrg?.id || ""; const integrationSlug = useSearch({ @@ -50,10 +50,10 @@ export const SelectIntegrationAuthPage = () => { if (integrationSlug === "github") { const sameProjectIntegrationAuths = filteredIntegrationAuths.filter( - (auth) => auth.projectId === currentWorkspace?.id + (auth) => auth.projectId === currentProject?.id ); const differentProjectIntegrationAuths = filteredIntegrationAuths.filter( - (auth) => auth.projectId !== currentWorkspace?.id + (auth) => auth.projectId !== currentProject?.id ); const installationIds = new Set(); @@ -117,11 +117,11 @@ export const SelectIntegrationAuthPage = () => { const handleConnectionSelect = async (integrationAuth: IntegrationAuth) => { if (integrationSlug === "github") { - if (integrationAuth.projectId === currentWorkspace?.id) { + if (integrationAuth.projectId === currentProject?.id) { navigate({ to: "/projects/secret-management/$projectId/integrations/github/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id @@ -130,14 +130,14 @@ export const SelectIntegrationAuthPage = () => { } else { // we create a copy of the existing integration auth from another project to the current project const newIntegrationAuth = await duplicateIntegrationAuth({ - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", integrationAuthId: integrationAuth.id }); navigate({ to: "/projects/secret-management/$projectId/integrations/github/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: newIntegrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/SupabaseAuthorizePage/SupabaseAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/SupabaseAuthorizePage/SupabaseAuthorizePage.tsx index 5ec969e11..210efea1c 100644 --- a/frontend/src/pages/secret-manager/integrations/SupabaseAuthorizePage/SupabaseAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/SupabaseAuthorizePage/SupabaseAuthorizePage.tsx @@ -2,13 +2,13 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const SupabaseAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); @@ -25,7 +25,7 @@ export const SupabaseAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "supabase", accessToken: apiKey }); @@ -35,7 +35,7 @@ export const SupabaseAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/supabase/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/SupabaseConfigurePage/SupabaseConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/SupabaseConfigurePage/SupabaseConfigurePage.tsx index 333c61a8e..38183a5ad 100644 --- a/frontend/src/pages/secret-manager/integrations/SupabaseConfigurePage/SupabaseConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/SupabaseConfigurePage/SupabaseConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -22,7 +22,7 @@ import { IntegrationsListPageTabs } from "@app/types/integrations"; export const SupabaseConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.SupabaseConfigurePage.id, select: (el) => el.integrationAuthId @@ -34,7 +34,7 @@ export const SupabaseConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); const [targetApp, setTargetApp] = useState(""); @@ -73,7 +73,7 @@ export const SupabaseConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -94,7 +94,7 @@ export const SupabaseConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [serverUrl, setServerUrl] = useState(""); @@ -37,7 +37,7 @@ export const TeamcityAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "teamcity", accessToken: apiKey, url: serverUrl @@ -48,7 +48,7 @@ export const TeamcityAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/teamcity/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/TeamcityConfigurePage/TeamcityConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/TeamcityConfigurePage/TeamcityConfigurePage.tsx index 9291d0d5f..8e7d0fe97 100644 --- a/frontend/src/pages/secret-manager/integrations/TeamcityConfigurePage/TeamcityConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/TeamcityConfigurePage/TeamcityConfigurePage.tsx @@ -14,7 +14,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -26,7 +26,7 @@ import { IntegrationsListPageTabs } from "@app/types/integrations"; export const TeamcityConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.TeamcityConfigurePage.id, @@ -34,7 +34,7 @@ export const TeamcityConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetAppId, setTargetAppId] = useState(""); const [targetBuildConfigId, setTargetBuildConfigId] = useState(""); @@ -92,7 +92,7 @@ export const TeamcityConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -149,7 +149,7 @@ export const TeamcityConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); @@ -37,7 +37,7 @@ export const TerraformCloudAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "terraform-cloud", accessId: workspacesId, accessToken: apiKey @@ -48,7 +48,7 @@ export const TerraformCloudAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/terraform-cloud/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/TerraformCloudConfigurePage/TerraformCloudConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/TerraformCloudConfigurePage/TerraformCloudConfigurePage.tsx index a2d73feca..ba44dfaa4 100644 --- a/frontend/src/pages/secret-manager/integrations/TerraformCloudConfigurePage/TerraformCloudConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/TerraformCloudConfigurePage/TerraformCloudConfigurePage.tsx @@ -14,7 +14,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -44,7 +44,7 @@ export const TerraformCloudConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.TerraformCloudConfigurePage.id, @@ -56,7 +56,7 @@ export const TerraformCloudConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetApp, setTargetApp] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -107,7 +107,7 @@ export const TerraformCloudConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -160,7 +160,7 @@ export const TerraformCloudConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { mutateAsync } = useSaveIntegrationAccessToken(); const [apiKey, setApiKey] = useState(""); @@ -25,7 +25,7 @@ export const TravisCIAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "travisci", accessToken: apiKey }); @@ -35,7 +35,7 @@ export const TravisCIAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/travisci/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/TravisCIConfigurePage/TravisCIConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/TravisCIConfigurePage/TravisCIConfigurePage.tsx index 66c3a8022..e71a6ab31 100644 --- a/frontend/src/pages/secret-manager/integrations/TravisCIConfigurePage/TravisCIConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/TravisCIConfigurePage/TravisCIConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -23,7 +23,7 @@ export const TravisCIConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.TravisCIConfigurePage.id, @@ -36,7 +36,7 @@ export const TravisCIConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [targetApp, setTargetApp] = useState(""); const [secretPath, setSecretPath] = useState("/"); @@ -74,7 +74,7 @@ export const TravisCIConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -95,7 +95,7 @@ export const TravisCIConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); const [initialSyncBehavior, setInitialSyncBehavior] = useState( @@ -134,7 +134,7 @@ export const VercelConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -206,7 +206,7 @@ export const VercelConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { @@ -12,7 +12,7 @@ export const VercelOauthCallbackPage = () => { const { code, state } = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.VercelOauthCallbackPage.id }); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); useEffect(() => { (async () => { @@ -22,7 +22,7 @@ export const VercelOauthCallbackPage = () => { localStorage.removeItem("latestCSRFToken"); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, code: code as string, integration: "vercel" }); @@ -30,7 +30,7 @@ export const VercelOauthCallbackPage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/vercel/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/WindmillAuthorizePage/WindmillAuthorizePage.tsx b/frontend/src/pages/secret-manager/integrations/WindmillAuthorizePage/WindmillAuthorizePage.tsx index 36e791e56..3cd3ff335 100644 --- a/frontend/src/pages/secret-manager/integrations/WindmillAuthorizePage/WindmillAuthorizePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/WindmillAuthorizePage/WindmillAuthorizePage.tsx @@ -2,14 +2,14 @@ import { useState } from "react"; import { useNavigate } from "@tanstack/react-router"; import { Button, Card, CardTitle, FormControl, Input } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { isInfisicalCloud } from "@app/helpers/platform"; import { useSaveIntegrationAccessToken } from "@app/hooks/api"; export const WindmillAuthorizePage = () => { const navigate = useNavigate(); const { mutateAsync } = useSaveIntegrationAccessToken(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [apiKey, setApiKey] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState(""); const [apiUrl, setApiUrl] = useState(null); @@ -68,7 +68,7 @@ export const WindmillAuthorizePage = () => { setIsLoading(true); const integrationAuth = await mutateAsync({ - workspaceId: currentWorkspace.id, + workspaceId: currentProject.id, integration: "windmill", accessToken: apiKey, url: apiUrl ?? undefined @@ -79,7 +79,7 @@ export const WindmillAuthorizePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations/windmill/create", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { integrationAuthId: integrationAuth.id diff --git a/frontend/src/pages/secret-manager/integrations/WindmillConfigurePage/WindmillConfigurePage.tsx b/frontend/src/pages/secret-manager/integrations/WindmillConfigurePage/WindmillConfigurePage.tsx index 17929b2a3..7f781c89e 100644 --- a/frontend/src/pages/secret-manager/integrations/WindmillConfigurePage/WindmillConfigurePage.tsx +++ b/frontend/src/pages/secret-manager/integrations/WindmillConfigurePage/WindmillConfigurePage.tsx @@ -11,7 +11,7 @@ import { SelectItem } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateIntegration } from "@app/hooks/api"; import { useGetIntegrationAuthApps, @@ -23,7 +23,7 @@ export const WindmillConfigurePage = () => { const navigate = useNavigate(); const { mutateAsync } = useCreateIntegration(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.WindmillConfigurePage.id, @@ -36,7 +36,7 @@ export const WindmillConfigurePage = () => { }); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState( - currentWorkspace.environments[0].slug + currentProject.environments[0].slug ); const [secretPath, setSecretPath] = useState("/"); const [targetApp, setTargetApp] = useState(""); @@ -76,7 +76,7 @@ export const WindmillConfigurePage = () => { navigate({ to: "/projects/secret-management/$projectId/integrations", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { selectedTab: IntegrationsListPageTabs.NativeIntegrations @@ -97,7 +97,7 @@ export const WindmillConfigurePage = () => { onValueChange={(val) => setSelectedSourceEnvironment(val)} className="w-full border border-mineshaft-500" > - {currentWorkspace?.environments.map((sourceEnvironment) => ( + {currentProject?.environments.map((sourceEnvironment) => ( { const project = await context.queryClient.ensureQueryData({ - queryKey: workspaceKeys.getWorkspaceById(params.projectId), - queryFn: () => fetchWorkspaceById(params.projectId) + queryKey: projectKeys.getProjectById(params.projectId), + queryFn: () => fetchProjectById(params.projectId) }); await context.queryClient.ensureQueryData({ queryKey: roleQueryKeys.getUserProjectPermissions({ - workspaceId: params.projectId + projectId: params.projectId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId: params.projectId }) + queryFn: () => fetchUserProjectPermissions({ projectId: params.projectId }) }); return { diff --git a/frontend/src/pages/secret-scanning/SecretScanningDataSourceByIdPage/components/SecretScanningScanRow.tsx b/frontend/src/pages/secret-scanning/SecretScanningDataSourceByIdPage/components/SecretScanningScanRow.tsx index 6dc7ceb35..804c4d790 100644 --- a/frontend/src/pages/secret-scanning/SecretScanningDataSourceByIdPage/components/SecretScanningScanRow.tsx +++ b/frontend/src/pages/secret-scanning/SecretScanningDataSourceByIdPage/components/SecretScanningScanRow.tsx @@ -18,7 +18,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useToggle } from "@app/hooks"; import { SecretScanningScanStatus, @@ -41,7 +41,7 @@ export const SecretScanningScanRow = ({ scan }: Props) => { resolvedFindings, type } = scan; - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const totalFindings = resolvedFindings + unresolvedFindings; const navigate = useNavigate(); @@ -97,7 +97,7 @@ export const SecretScanningScanRow = ({ scan }: Props) => { navigate({ to: "/projects/secret-scanning/$projectId/findings", params: { - projectId: currentWorkspace.id + projectId: currentProject.id }, search: { search: `scanId:${id}` diff --git a/frontend/src/pages/secret-scanning/SecretScanningDataSourcesPage/components/SecretScanningDataSourcesSection.tsx b/frontend/src/pages/secret-scanning/SecretScanningDataSourcesPage/components/SecretScanningDataSourcesSection.tsx index 019ca3467..03c387440 100644 --- a/frontend/src/pages/secret-scanning/SecretScanningDataSourcesPage/components/SecretScanningDataSourcesSection.tsx +++ b/frontend/src/pages/secret-scanning/SecretScanningDataSourcesPage/components/SecretScanningDataSourcesSection.tsx @@ -5,7 +5,7 @@ import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { ProjectPermissionCan } from "@app/components/permissions"; import { CreateSecretScanningDataSourceModal } from "@app/components/secret-scanning"; import { Button, Spinner } from "@app/components/v2"; -import { ProjectPermissionSub, useSubscription, useWorkspace } from "@app/context"; +import { ProjectPermissionSub, useProject, useSubscription } from "@app/context"; import { ProjectPermissionSecretScanningDataSourceActions } from "@app/context/ProjectPermissionContext/types"; import { usePopUp } from "@app/hooks"; import { useListSecretScanningDataSources } from "@app/hooks/api/secretScanningV2"; @@ -20,10 +20,10 @@ export const SecretScanningDataSourcesSection = () => { const { subscription } = useSubscription(); - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: dataSources = [], isPending: isDataSourcesPending } = - useListSecretScanningDataSources(currentWorkspace.id, { + useListSecretScanningDataSources(currentProject.id, { refetchInterval: 30000, enabled: subscription.secretScanning }); diff --git a/frontend/src/pages/secret-scanning/SecretScanningFindingsPage/components/SecretScanningFindingsSection.tsx b/frontend/src/pages/secret-scanning/SecretScanningFindingsPage/components/SecretScanningFindingsSection.tsx index 82ea049f9..4a9cf1ad0 100644 --- a/frontend/src/pages/secret-scanning/SecretScanningFindingsPage/components/SecretScanningFindingsSection.tsx +++ b/frontend/src/pages/secret-scanning/SecretScanningFindingsPage/components/SecretScanningFindingsSection.tsx @@ -2,16 +2,16 @@ import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-sv import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { ContentLoader } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useListSecretScanningFindings } from "@app/hooks/api/secretScanningV2"; import { SecretScanningFindingsTable } from "./SecretScanningFindingsTable"; export const SecretScanningFindingsSection = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: findings = [], isPending: isFindingsPending } = useListSecretScanningFindings( - currentWorkspace.id, + currentProject.id, { refetchInterval: 30000 } diff --git a/frontend/src/pages/secret-scanning/SettingsPage/components/ProjectScanningConfigTab/ProjectScanningConfigTab.tsx b/frontend/src/pages/secret-scanning/SettingsPage/components/ProjectScanningConfigTab/ProjectScanningConfigTab.tsx index e8d3206d8..4cf9e2b22 100644 --- a/frontend/src/pages/secret-scanning/SettingsPage/components/ProjectScanningConfigTab/ProjectScanningConfigTab.tsx +++ b/frontend/src/pages/secret-scanning/SettingsPage/components/ProjectScanningConfigTab/ProjectScanningConfigTab.tsx @@ -1,16 +1,16 @@ import { faBan } from "@fortawesome/free-solid-svg-icons"; import { AccessRestrictedBanner, ContentLoader, EmptyState } from "@app/components/v2"; -import { useSubscription, useWorkspace } from "@app/context"; +import { useProject, useSubscription } from "@app/context"; import { useGetSecretScanningConfig } from "@app/hooks/api/secretScanningV2"; import { SecretScanningConfigForm } from "./SecretScanningConfigForm"; export const ProjectScanningConfigTab = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { subscription } = useSubscription(); const { data: config, isPending: isConfigPending } = useGetSecretScanningConfig( - currentWorkspace.id, + currentProject.id, { enabled: subscription.secretScanning } ); diff --git a/frontend/src/pages/secret-scanning/layout.tsx b/frontend/src/pages/secret-scanning/layout.tsx index 38899a233..13a43f895 100644 --- a/frontend/src/pages/secret-scanning/layout.tsx +++ b/frontend/src/pages/secret-scanning/layout.tsx @@ -1,9 +1,9 @@ import { createFileRoute } from "@tanstack/react-router"; import { BreadcrumbTypes } from "@app/components/v2"; -import { workspaceKeys } from "@app/hooks/api"; +import { projectKeys } from "@app/hooks/api"; +import { fetchProjectById } from "@app/hooks/api/projects/queries"; import { fetchUserProjectPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries"; -import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries"; import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect"; import { SecretScanningLayout } from "@app/layouts/SecretScanningLayout"; @@ -13,15 +13,15 @@ export const Route = createFileRoute( component: SecretScanningLayout, beforeLoad: async ({ params, context }) => { const project = await context.queryClient.ensureQueryData({ - queryKey: workspaceKeys.getWorkspaceById(params.projectId), - queryFn: () => fetchWorkspaceById(params.projectId) + queryKey: projectKeys.getProjectById(params.projectId), + queryFn: () => fetchProjectById(params.projectId) }); await context.queryClient.ensureQueryData({ queryKey: roleQueryKeys.getUserProjectPermissions({ - workspaceId: params.projectId + projectId: params.projectId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId: params.projectId }) + queryFn: () => fetchUserProjectPermissions({ projectId: params.projectId }) }); return { diff --git a/frontend/src/pages/ssh/SettingsPage/components/ProjectSshTab/components/ProjectSshConfigCasSection.tsx b/frontend/src/pages/ssh/SettingsPage/components/ProjectSshTab/components/ProjectSshConfigCasSection.tsx index 503717326..7b00b3ea0 100644 --- a/frontend/src/pages/ssh/SettingsPage/components/ProjectSshTab/components/ProjectSshConfigCasSection.tsx +++ b/frontend/src/pages/ssh/SettingsPage/components/ProjectSshTab/components/ProjectSshConfigCasSection.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { Button, FormControl, Select, SelectItem } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useGetProjectSshConfig, useListWorkspaceSshCas, @@ -23,9 +23,9 @@ const schema = z export type FormData = z.infer; export const ProjectSshConfigCasSection = () => { - const { currentWorkspace } = useWorkspace(); - const { data: sshConfig } = useGetProjectSshConfig(currentWorkspace.id); - const { data: sshCas } = useListWorkspaceSshCas(currentWorkspace.id); + const { currentProject } = useProject(); + const { data: sshConfig } = useGetProjectSshConfig(currentProject.id); + const { data: sshCas } = useListWorkspaceSshCas(currentProject.id); const { mutate: updateProjectSshConfig } = useUpdateProjectSshConfig(); const { @@ -49,7 +49,7 @@ export const ProjectSshConfigCasSection = () => { const onFormSubmit = async ({ defaultUserSshCaId, defaultHostSshCaId }: FormData) => { try { await updateProjectSshConfig({ - projectId: currentWorkspace.id, + projectId: currentProject.id, defaultUserSshCaId: defaultUserSshCaId || undefined, defaultHostSshCaId: defaultHostSshCaId || undefined }); diff --git a/frontend/src/pages/ssh/SshCaByIDPage/SshCaByIDPage.tsx b/frontend/src/pages/ssh/SshCaByIDPage/SshCaByIDPage.tsx index 8bed6e647..88a8c7f60 100644 --- a/frontend/src/pages/ssh/SshCaByIDPage/SshCaByIDPage.tsx +++ b/frontend/src/pages/ssh/SshCaByIDPage/SshCaByIDPage.tsx @@ -15,7 +15,7 @@ import { Tooltip } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useDeleteSshCa, useGetSshCaById } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -23,9 +23,9 @@ import { SshCaModal } from "../SshCasPage/components/SshCaModal"; import { SshCaDetailsSection, SshCertificateTemplatesSection } from "./components"; const Page = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); - const projectId = currentWorkspace?.id || ""; + const projectId = currentProject?.id || ""; const caId = useParams({ from: ROUTE_PATHS.Ssh.SshCaByIDPage.id, select: (el) => el.caId diff --git a/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateModal.tsx b/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateModal.tsx index 5c4673931..6e0baa502 100644 --- a/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateModal.tsx +++ b/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateModal.tsx @@ -14,7 +14,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { SshCertTemplateStatus, useGetSshCertTemplate, @@ -71,8 +71,8 @@ enum SshCertificateOperation { } export const SshCertificateModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const [operation, setOperation] = useState( SshCertificateOperation.SIGN_SSH_KEY ); diff --git a/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateTemplateModal.tsx b/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateTemplateModal.tsx index 55d4104ac..17c7a552e 100644 --- a/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateTemplateModal.tsx +++ b/frontend/src/pages/ssh/SshCaByIDPage/components/SshCertificateTemplateModal.tsx @@ -16,7 +16,7 @@ import { SelectItem, Switch } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateSshCertTemplate, useGetSshCaById, @@ -77,7 +77,7 @@ type Props = { }; export const SshCertificateTemplateModal = ({ popUp, handlePopUpToggle, sshCaId }: Props) => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const { data: ca } = useGetSshCaById(sshCaId); @@ -85,7 +85,7 @@ export const SshCertificateTemplateModal = ({ popUp, handlePopUpToggle, sshCaId (popUp?.sshCertificateTemplate?.data as { id: string })?.id || "" ); - const { data: cas } = useListWorkspaceSshCas(currentWorkspace?.id || ""); + const { data: cas } = useListWorkspaceSshCas(currentProject?.id || ""); const { mutateAsync: createSshCertTemplate } = useCreateSshCertTemplate(); const { mutateAsync: updateSshCertTemplate } = useUpdateSshCertTemplate(); diff --git a/frontend/src/pages/ssh/SshCasPage/components/SshCaModal.tsx b/frontend/src/pages/ssh/SshCasPage/components/SshCaModal.tsx index 758af52a9..4c8ce4e19 100644 --- a/frontend/src/pages/ssh/SshCasPage/components/SshCaModal.tsx +++ b/frontend/src/pages/ssh/SshCasPage/components/SshCaModal.tsx @@ -15,7 +15,7 @@ import { SelectItem, TextArea } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateSshCa, useGetSshCaById, useUpdateSshCa } from "@app/hooks/api"; import { SshCaKeySource, @@ -54,8 +54,8 @@ export type FormData = z.infer; export const SshCaModal = ({ popUp, handlePopUpToggle }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; const { data: ca } = useGetSshCaById((popUp?.sshCa?.data as { caId: string })?.caId || ""); const { mutateAsync: createMutateAsync } = useCreateSshCa(); diff --git a/frontend/src/pages/ssh/SshCasPage/components/SshCaTable.tsx b/frontend/src/pages/ssh/SshCasPage/components/SshCaTable.tsx index 37a086f37..c94f73664 100644 --- a/frontend/src/pages/ssh/SshCasPage/components/SshCaTable.tsx +++ b/frontend/src/pages/ssh/SshCasPage/components/SshCaTable.tsx @@ -21,7 +21,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { SshCaStatus, useListWorkspaceSshCas } from "@app/hooks/api"; import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -35,8 +35,8 @@ type Props = { export const SshCaTable = ({ handlePopUpOpen }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useListWorkspaceSshCas(currentWorkspace?.id || ""); + const { currentProject } = useProject(); + const { data, isPending } = useListWorkspaceSshCas(currentProject?.id || ""); return (
@@ -63,7 +63,7 @@ export const SshCaTable = ({ handlePopUpOpen }: Props) => { navigate({ to: "/projects/ssh/$projectId/ca/$caId", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, caId: ca.id } }) diff --git a/frontend/src/pages/ssh/SshCertsPage/components/SshCertificatesTable.tsx b/frontend/src/pages/ssh/SshCertsPage/components/SshCertificatesTable.tsx index c48b407ac..1ebf3112c 100644 --- a/frontend/src/pages/ssh/SshCertsPage/components/SshCertificatesTable.tsx +++ b/frontend/src/pages/ssh/SshCertsPage/components/SshCertificatesTable.tsx @@ -15,7 +15,7 @@ import { THead, Tr } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useListWorkspaceSshCertificates } from "@app/hooks/api"; import { getSshCertStatusBadgeDetails } from "./SshCertificatesTable.utils"; @@ -23,12 +23,12 @@ import { getSshCertStatusBadgeDetails } from "./SshCertificatesTable.utils"; const PER_PAGE_INIT = 25; export const SshCertificatesTable = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const [page, setPage] = useState(1); const [perPage, setPerPage] = useState(PER_PAGE_INIT); const { data, isPending } = useListWorkspaceSshCertificates({ - projectId: currentWorkspace?.id || "", + projectId: currentProject?.id || "", offset: (page - 1) * perPage, limit: perPage }); diff --git a/frontend/src/pages/ssh/SshHostGroupDetailsByIDPage/SshHostGroupDetailsByIDPage.tsx b/frontend/src/pages/ssh/SshHostGroupDetailsByIDPage/SshHostGroupDetailsByIDPage.tsx index 6b43e8324..e030a8fa0 100644 --- a/frontend/src/pages/ssh/SshHostGroupDetailsByIDPage/SshHostGroupDetailsByIDPage.tsx +++ b/frontend/src/pages/ssh/SshHostGroupDetailsByIDPage/SshHostGroupDetailsByIDPage.tsx @@ -16,7 +16,7 @@ import { Tooltip } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useDeleteSshHostGroup, useGetSshHostGroupById } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; @@ -24,9 +24,9 @@ import { SshHostGroupModal } from "../SshHostsPage/components/SshHostGroupModal" import { SshHostGroupDetailsSection, SshHostGroupHostsSection } from "./components"; const Page = () => { - const { currentWorkspace } = useWorkspace(); + const { currentProject } = useProject(); const navigate = useNavigate(); - const projectId = currentWorkspace?.id || ""; + const projectId = currentProject?.id || ""; const sshHostGroupId = useParams({ from: ROUTE_PATHS.Ssh.SshHostGroupDetailsByIDPage.id, select: (el) => el.sshHostGroupId diff --git a/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupModal.tsx b/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupModal.tsx index 84be5a96d..4905695d4 100644 --- a/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupModal.tsx +++ b/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupModal.tsx @@ -17,7 +17,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateSshHostGroup, useGetSshHostGroupById, @@ -56,8 +56,8 @@ const schema = z export type FormData = z.infer; export const SshHostGroupModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace.id; + const { currentProject } = useProject(); + const projectId = currentProject.id; const { data: sshHostGroups } = useListWorkspaceSshHostGroups(projectId); const { data: members = [] } = useGetWorkspaceUsers(projectId); const { data: groups = [] } = useListWorkspaceGroups(projectId); diff --git a/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupsTable.tsx b/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupsTable.tsx index daedabdc9..af3a97dc6 100644 --- a/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupsTable.tsx +++ b/frontend/src/pages/ssh/SshHostsPage/components/SshHostGroupsTable.tsx @@ -28,7 +28,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context"; import { useListWorkspaceSshHostGroups } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -41,8 +41,8 @@ type Props = { export const SshHostGroupsTable = ({ handlePopUpOpen }: Props) => { const navigate = useNavigate(); - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useListWorkspaceSshHostGroups(currentWorkspace?.id || ""); + const { currentProject } = useProject(); + const { data, isPending } = useListWorkspaceSshHostGroups(currentProject?.id || ""); return (
@@ -69,7 +69,7 @@ export const SshHostGroupsTable = ({ handlePopUpOpen }: Props) => { navigate({ to: "/projects/ssh/$projectId/ssh-host-groups/$sshHostGroupId", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, sshHostGroupId: group.id } }) @@ -170,7 +170,7 @@ export const SshHostGroupsTable = ({ handlePopUpOpen }: Props) => { navigate({ to: "/projects/ssh/$projectId/ssh-host-groups/$sshHostGroupId", params: { - projectId: currentWorkspace.id, + projectId: currentProject.id, sshHostGroupId: group.id } }); diff --git a/frontend/src/pages/ssh/SshHostsPage/components/SshHostModal.tsx b/frontend/src/pages/ssh/SshHostsPage/components/SshHostModal.tsx index 5619a75c4..e1ea75143 100644 --- a/frontend/src/pages/ssh/SshHostsPage/components/SshHostModal.tsx +++ b/frontend/src/pages/ssh/SshHostsPage/components/SshHostModal.tsx @@ -18,7 +18,7 @@ import { Select, SelectItem } from "@app/components/v2"; -import { useWorkspace } from "@app/context"; +import { useProject } from "@app/context"; import { useCreateSshHost, useGetSshHostById, @@ -68,9 +68,9 @@ const schema = z export type FormData = z.infer; export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => { - const { currentWorkspace } = useWorkspace(); - const projectId = currentWorkspace?.id || ""; - const { data: sshHosts } = useListWorkspaceSshHosts(currentWorkspace.id); + const { currentProject } = useProject(); + const projectId = currentProject?.id || ""; + const { data: sshHosts } = useListWorkspaceSshHosts(currentProject.id); const { data: members = [] } = useGetWorkspaceUsers(projectId); const { data: groups = [] } = useListWorkspaceGroups(projectId); const [expandedMappings, setExpandedMappings] = useState>({}); diff --git a/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx b/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx index 62f563cce..f29f0147e 100644 --- a/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx +++ b/frontend/src/pages/ssh/SshHostsPage/components/SshHostsTable.tsx @@ -30,7 +30,7 @@ import { Tooltip, Tr } from "@app/components/v2"; -import { ProjectPermissionSshHostActions, ProjectPermissionSub, useWorkspace } from "@app/context"; +import { ProjectPermissionSshHostActions, ProjectPermissionSub, useProject } from "@app/context"; import { fetchSshHostUserCaPublicKey, useListWorkspaceSshHosts } from "@app/hooks/api"; import { LoginMappingSource } from "@app/hooks/api/sshHost/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; @@ -43,8 +43,8 @@ type Props = { }; export const SshHostsTable = ({ handlePopUpOpen }: Props) => { - const { currentWorkspace } = useWorkspace(); - const { data, isPending } = useListWorkspaceSshHosts(currentWorkspace?.id || ""); + const { currentProject } = useProject(); + const { data, isPending } = useListWorkspaceSshHosts(currentProject?.id || ""); const downloadTxtFile = (filename: string, content: string) => { const blob = new Blob([content], { type: "text/plain;charset=utf-8" }); diff --git a/frontend/src/pages/ssh/layout.tsx b/frontend/src/pages/ssh/layout.tsx index 008aca393..9b1a0057b 100644 --- a/frontend/src/pages/ssh/layout.tsx +++ b/frontend/src/pages/ssh/layout.tsx @@ -1,9 +1,9 @@ import { createFileRoute } from "@tanstack/react-router"; import { BreadcrumbTypes } from "@app/components/v2"; -import { workspaceKeys } from "@app/hooks/api"; +import { projectKeys } from "@app/hooks/api"; +import { fetchProjectById } from "@app/hooks/api/projects/queries"; import { fetchUserProjectPermissions, roleQueryKeys } from "@app/hooks/api/roles/queries"; -import { fetchWorkspaceById } from "@app/hooks/api/workspace/queries"; import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect"; import { SshLayout } from "@app/layouts/SshLayout"; @@ -13,15 +13,15 @@ export const Route = createFileRoute( component: SshLayout, beforeLoad: async ({ params, context }) => { const project = await context.queryClient.ensureQueryData({ - queryKey: workspaceKeys.getWorkspaceById(params.projectId), - queryFn: () => fetchWorkspaceById(params.projectId) + queryKey: projectKeys.getProjectById(params.projectId), + queryFn: () => fetchProjectById(params.projectId) }); await context.queryClient.ensureQueryData({ queryKey: roleQueryKeys.getUserProjectPermissions({ - workspaceId: params.projectId + projectId: params.projectId }), - queryFn: () => fetchUserProjectPermissions({ workspaceId: params.projectId }) + queryFn: () => fetchUserProjectPermissions({ projectId: params.projectId }) }); return {