diff --git a/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.test.tsx b/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.test.tsx index 0078f5eabb..e5e142508f 100644 --- a/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.test.tsx +++ b/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.test.tsx @@ -1,4 +1,3 @@ -import { ApiKeyPermission } from "@prisma/client"; import "@testing-library/jest-dom/vitest"; import { cleanup, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; @@ -123,6 +122,9 @@ describe("AddApiKeyModal", () => { it("handles permission changes", async () => { render(); + const addButton = screen.getByRole("button", { name: /add_permission/i }); + await userEvent.click(addButton); + // Open project dropdown for the first permission row const projectDropdowns = screen.getAllByRole("button", { name: /Project 1/i }); await userEvent.click(projectDropdowns[0]); @@ -143,6 +145,8 @@ describe("AddApiKeyModal", () => { const addButton = screen.getByRole("button", { name: /add_permission/i }); await userEvent.click(addButton); + await userEvent.click(addButton); + // Verify new permission row is added const deleteButtons = screen.getAllByRole("button", { name: "" }); // Trash icons expect(deleteButtons).toHaveLength(2); @@ -161,6 +165,9 @@ describe("AddApiKeyModal", () => { const labelInput = screen.getByPlaceholderText("e.g. GitHub, PostHog, Slack") as HTMLInputElement; await userEvent.type(labelInput, "Test API Key"); + const addButton = screen.getByRole("button", { name: /add_permission/i }); + await userEvent.click(addButton); + // Click submit const submitButton = screen.getByRole("button", { name: "environments.project.api_keys.add_api_key", @@ -172,7 +179,7 @@ describe("AddApiKeyModal", () => { environmentPermissions: [ { environmentId: "env1", - permission: ApiKeyPermission.read, + permission: "read", }, ], organizationAccess: { @@ -203,12 +210,7 @@ describe("AddApiKeyModal", () => { expect(mockOnSubmit).toHaveBeenCalledWith({ label: "Test API Key", - environmentPermissions: [ - { - environmentId: "env1", - permission: ApiKeyPermission.read, - }, - ], + environmentPermissions: [], organizationAccess: { accessControl: { read: true, @@ -218,7 +220,7 @@ describe("AddApiKeyModal", () => { }); }); - it("disables submit button when label is empty", async () => { + it("disables submit button when label is empty and there are not environment permissions", async () => { render(); const submitButton = screen.getByRole("button", { name: "environments.project.api_keys.add_api_key", @@ -228,6 +230,9 @@ describe("AddApiKeyModal", () => { // Initially disabled expect(submitButton).toBeDisabled(); + const addButton = screen.getByRole("button", { name: /add_permission/i }); + await userEvent.click(addButton); + // After typing, it should be enabled await userEvent.type(labelInput, "Test"); expect(submitButton).not.toBeDisabled(); diff --git a/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.tsx b/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.tsx index f6f0c5515a..16b679c68b 100644 --- a/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.tsx +++ b/apps/web/modules/organization/settings/api-keys/components/add-api-key-modal.tsx @@ -89,9 +89,7 @@ export const AddApiKeyModal = ({ }; // Initialize with one permission by default - const [selectedPermissions, setSelectedPermissions] = useState>(() => - getInitialPermissions() - ); + const [selectedPermissions, setSelectedPermissions] = useState>({}); const projectOptions: ProjectOption[] = projects.map((project) => ({ id: project.id, @@ -106,14 +104,12 @@ export const AddApiKeyModal = ({ const addPermission = () => { const newIndex = Object.keys(selectedPermissions).length; - if (projects.length > 0 && projects[0].environments.length > 0) { - const initialPermission = getInitialPermissions()["permission-0"]; - if (initialPermission) { - setSelectedPermissions({ - ...selectedPermissions, - [`permission-${newIndex}`]: initialPermission, - }); - } + const initialPermission = getInitialPermissions()["permission-0"]; + if (initialPermission) { + setSelectedPermissions({ + ...selectedPermissions, + [`permission-${newIndex}`]: initialPermission, + }); } }; @@ -176,7 +172,7 @@ export const AddApiKeyModal = ({ }); reset(); - setSelectedPermissions(getInitialPermissions()); + setSelectedPermissions({}); setSelectedOrganizationAccess(defaultOrganizationAccess); }; @@ -191,11 +187,16 @@ export const AddApiKeyModal = ({ if (!apiKeyLabel?.trim()) { return true; } - // Check if there are any valid permissions - if (Object.keys(selectedPermissions).length === 0) { - return true; - } - return false; + + // Check if at least one project permission is set or one organization access toggle is ON + const hasProjectAccess = Object.keys(selectedPermissions).length > 0; + + const hasOrganizationAccess = Object.values(selectedOrganizationAccess).some((accessGroup) => + Object.values(accessGroup).some((value) => value === true) + ); + + // Disable submit if no access rights are granted + return !(hasProjectAccess || hasOrganizationAccess); }; const setSelectedOrganizationAccessValue = (key: string, accessType: string, value: boolean) => { @@ -335,15 +336,8 @@ export const AddApiKeyModal = ({ ); @@ -403,7 +397,7 @@ export const AddApiKeyModal = ({ onClick={() => { setOpen(false); reset(); - setSelectedPermissions(getInitialPermissions()); + setSelectedPermissions({}); }}> {t("common.cancel")} diff --git a/apps/web/modules/organization/settings/api-keys/components/edit-api-keys.test.tsx b/apps/web/modules/organization/settings/api-keys/components/edit-api-keys.test.tsx index 94d558f3fc..7e9b0e3029 100644 --- a/apps/web/modules/organization/settings/api-keys/components/edit-api-keys.test.tsx +++ b/apps/web/modules/organization/settings/api-keys/components/edit-api-keys.test.tsx @@ -265,7 +265,7 @@ describe("EditAPIKeys", () => { organizationId: "org1", apiKeyData: { label: "New Key", - environmentPermissions: [{ environmentId: "env1", permission: ApiKeyPermission.read }], + environmentPermissions: [], organizationAccess: { accessControl: { read: true, write: false }, }, diff --git a/apps/web/modules/organization/settings/api-keys/components/view-permission-modal.tsx b/apps/web/modules/organization/settings/api-keys/components/view-permission-modal.tsx index 7c69d6869d..9790bab9e2 100644 --- a/apps/web/modules/organization/settings/api-keys/components/view-permission-modal.tsx +++ b/apps/web/modules/organization/settings/api-keys/components/view-permission-modal.tsx @@ -98,9 +98,15 @@ export const ViewPermissionModal = ({ data-testid="api-key-label" {...register("label", { required: true, validate: (value) => value.trim() !== "" })} /> + {/* Permission rows */}
+ {apiKey.apiKeyEnvironments?.length === 0 && ( +
+ {t("environments.project.api_keys.no_env_permissions_found")} +
+ )}
{/* Permission rows */} {apiKey.apiKeyEnvironments?.map((permission) => { diff --git a/apps/web/playwright/lib/utils.ts b/apps/web/playwright/lib/utils.ts index 8420ec2aef..6b2001b7b6 100644 --- a/apps/web/playwright/lib/utils.ts +++ b/apps/web/playwright/lib/utils.ts @@ -18,6 +18,7 @@ export async function loginAndGetApiKey(page: Page, users: UsersFixture) { await page.getByRole("button", { name: "Add API Key" }).isVisible(); await page.getByRole("button", { name: "Add API Key" }).click(); await page.getByPlaceholder("e.g. GitHub, PostHog, Slack").fill("E2E Test API Key"); + await page.getByRole("button", { name: "+ Add permission" }).click(); await page.getByRole("button", { name: "development" }).click(); await page.getByRole("menuitem", { name: "production" }).click(); await page.getByRole("button", { name: "read" }).click(); diff --git a/packages/lib/messages/de-DE.json b/packages/lib/messages/de-DE.json index 933896b57d..5c4b7ed3ba 100644 --- a/packages/lib/messages/de-DE.json +++ b/packages/lib/messages/de-DE.json @@ -788,6 +788,7 @@ "api_key_updated": "API-Schlüssel aktualisiert", "duplicate_access": "Doppelter Projektzugriff nicht erlaubt", "no_api_keys_yet": "Du hast noch keine API-Schlüssel", + "no_env_permissions_found": "Keine Umgebungsberechtigungen gefunden", "organization_access": "Organisationszugang", "permissions": "Berechtigungen", "project_access": "Projektzugriff", diff --git a/packages/lib/messages/en-US.json b/packages/lib/messages/en-US.json index e4bc7cf882..c479005af6 100644 --- a/packages/lib/messages/en-US.json +++ b/packages/lib/messages/en-US.json @@ -788,6 +788,7 @@ "api_key_updated": "API Key updated", "duplicate_access": "Duplicate project access not allowed", "no_api_keys_yet": "You don't have any API keys yet", + "no_env_permissions_found": "No environment permissions found", "organization_access": "Organization Access", "permissions": "Permissions", "project_access": "Project Access", diff --git a/packages/lib/messages/fr-FR.json b/packages/lib/messages/fr-FR.json index f0b9f79754..6ab6b72742 100644 --- a/packages/lib/messages/fr-FR.json +++ b/packages/lib/messages/fr-FR.json @@ -788,6 +788,7 @@ "api_key_updated": "Clé API mise à jour", "duplicate_access": "L'accès en double au projet n'est pas autorisé", "no_api_keys_yet": "Vous n'avez pas encore de clés API.", + "no_env_permissions_found": "Aucune autorisation d'environnement trouvée", "organization_access": "Accès à l'organisation", "permissions": "Permissions", "project_access": "Accès au projet", diff --git a/packages/lib/messages/pt-BR.json b/packages/lib/messages/pt-BR.json index 290155cfcd..c507ce5ed9 100644 --- a/packages/lib/messages/pt-BR.json +++ b/packages/lib/messages/pt-BR.json @@ -788,6 +788,7 @@ "api_key_updated": "Chave de API atualizada", "duplicate_access": "Acesso duplicado ao projeto não permitido", "no_api_keys_yet": "Você ainda não tem nenhuma chave de API", + "no_env_permissions_found": "Nenhuma permissão de ambiente encontrada", "organization_access": "Acesso à Organização", "permissions": "Permissões", "project_access": "Acesso ao Projeto", diff --git a/packages/lib/messages/pt-PT.json b/packages/lib/messages/pt-PT.json index a6e634c601..52baa2c69f 100644 --- a/packages/lib/messages/pt-PT.json +++ b/packages/lib/messages/pt-PT.json @@ -788,6 +788,7 @@ "api_key_updated": "Chave API atualizada", "duplicate_access": "Acesso duplicado ao projeto não permitido", "no_api_keys_yet": "Ainda não tem nenhuma chave API", + "no_env_permissions_found": "Nenhuma permissão de ambiente encontrada", "organization_access": "Acesso à Organização", "permissions": "Permissões", "project_access": "Acesso ao Projeto", diff --git a/packages/lib/messages/zh-Hant-TW.json b/packages/lib/messages/zh-Hant-TW.json index 6cb65cddac..18e4a32fd8 100644 --- a/packages/lib/messages/zh-Hant-TW.json +++ b/packages/lib/messages/zh-Hant-TW.json @@ -788,6 +788,7 @@ "api_key_updated": "API 金鑰已更新", "duplicate_access": "不允許重複的 project 存取", "no_api_keys_yet": "您還沒有任何 API 金鑰", + "no_env_permissions_found": "找不到環境權限", "organization_access": "組織 Access", "permissions": "權限", "project_access": "專案存取",