diff --git a/frontend/app/src/components/form/utils/mutations/getCreateMutationFromFormData.ts b/frontend/app/src/components/form/utils/mutations/getCreateMutationFromFormData.ts index d27f9de378..8d7550999e 100644 --- a/frontend/app/src/components/form/utils/mutations/getCreateMutationFromFormData.ts +++ b/frontend/app/src/components/form/utils/mutations/getCreateMutationFromFormData.ts @@ -63,7 +63,10 @@ export const getCreateMutationFromFormDataOnly = ( return { ...acc, - [name]: Array.isArray(fieldValue) ? fieldValue : { value: fieldValue }, + [name]: Array.isArray(fieldValue) + ? // Uses array of ids for relationships + fieldValue.map((value) => ({ id: value.id })) + : { value: fieldValue }, }; } diff --git a/frontend/app/src/components/modals/modal-delete-object.tsx b/frontend/app/src/components/modals/modal-delete-object.tsx index 2d91edeb4d..cc86c326bd 100644 --- a/frontend/app/src/components/modals/modal-delete-object.tsx +++ b/frontend/app/src/components/modals/modal-delete-object.tsx @@ -27,7 +27,11 @@ export default function ModalDeleteObject({ label, rowToDelete, open, close, onD const date = useAtomValue(datetimeAtom); const { objectKind } = useParams(); - const objectDisplay = rowToDelete?.display_label || rowToDelete?.name?.value || rowToDelete?.name; + const objectDisplay = + rowToDelete?.display_label?.value || + rowToDelete?.display_label || + rowToDelete?.name?.value || + rowToDelete?.name; const handleDeleteObject = async () => { if (!rowToDelete?.id) { diff --git a/frontend/app/src/components/ui/search-input.tsx b/frontend/app/src/components/ui/search-input.tsx index f79f2a08a9..c19145a42d 100644 --- a/frontend/app/src/components/ui/search-input.tsx +++ b/frontend/app/src/components/ui/search-input.tsx @@ -20,7 +20,12 @@ export const SearchInput = forwardRef( - {loading && } + {loading && ( + + )} ); } diff --git a/frontend/app/src/screens/role-management/account-form.tsx b/frontend/app/src/screens/role-management/account-form.tsx index 4fde745ce0..ae707daaf9 100644 --- a/frontend/app/src/screens/role-management/account-form.tsx +++ b/frontend/app/src/screens/role-management/account-form.tsx @@ -90,9 +90,15 @@ export const AccountForm = ({ }, }); - toast(, { - toastId: "alert-success-account-created", - }); + if (currentObject) { + toast(, { + toastId: "alert-success-account-updated", + }); + } else { + toast(, { + toastId: "alert-success-account-created", + }); + } if (onSuccess) await onSuccess(result?.data?.[`${OBJECT_PERMISSION_OBJECT}Create`]); if (onUpdateComplete) await onUpdateComplete(); diff --git a/frontend/app/src/screens/role-management/account-group-form.tsx b/frontend/app/src/screens/role-management/account-group-form.tsx index a178756c4a..7e843a7591 100644 --- a/frontend/app/src/screens/role-management/account-group-form.tsx +++ b/frontend/app/src/screens/role-management/account-group-form.tsx @@ -102,9 +102,15 @@ export const AccountGroupForm = ({ }, }); - toast(, { - toastId: "alert-success-group-created", - }); + if (currentObject) { + toast(, { + toastId: "alert-success-group-updated", + }); + } else { + toast(, { + toastId: "alert-success-group-created", + }); + } if (onSuccess) await onSuccess(result?.data?.[`${OBJECT_PERMISSION_OBJECT}Create`]); if (onUpdateComplete) await onUpdateComplete(); diff --git a/frontend/app/src/screens/role-management/account-role-form.tsx b/frontend/app/src/screens/role-management/account-role-form.tsx index 76e19e99a5..be76982eab 100644 --- a/frontend/app/src/screens/role-management/account-role-form.tsx +++ b/frontend/app/src/screens/role-management/account-role-form.tsx @@ -95,9 +95,15 @@ export const AccountRoleForm = ({ }, }); - toast(, { - toastId: "alert-success-role-created", - }); + if (currentObject) { + toast(, { + toastId: "alert-success-role-updated", + }); + } else { + toast(, { + toastId: "alert-success-role-created", + }); + } if (onSuccess) await onSuccess(result?.data?.[`${ACCOUNT_ROLE_OBJECT}Create`]); if (onUpdateComplete) await onUpdateComplete(); diff --git a/frontend/app/src/screens/role-management/global-permissions-form.tsx b/frontend/app/src/screens/role-management/global-permissions-form.tsx index 682d3ca941..14ff6face3 100644 --- a/frontend/app/src/screens/role-management/global-permissions-form.tsx +++ b/frontend/app/src/screens/role-management/global-permissions-form.tsx @@ -101,9 +101,15 @@ export const GlobalPermissionForm = ({ }, }); - toast(, { - toastId: "alert-success-object-permission-created", - }); + if (currentObject) { + toast(, { + toastId: "alert-success-global-permission-updated", + }); + } else { + toast(, { + toastId: "alert-success-global-permission-created", + }); + } if (onSuccess) await onSuccess(result?.data?.[`${GLOBAL_PERMISSION_OBJECT}Create`]); if (onUpdateComplete) await onUpdateComplete(); diff --git a/frontend/app/src/screens/role-management/global-permissions.tsx b/frontend/app/src/screens/role-management/global-permissions.tsx index 6bb2141050..3574085d85 100644 --- a/frontend/app/src/screens/role-management/global-permissions.tsx +++ b/frontend/app/src/screens/role-management/global-permissions.tsx @@ -76,7 +76,7 @@ function GlobalPermissions() { data[GLOBAL_PERMISSION_OBJECT]?.edges.map((edge) => { return { values: { - id: { value: edge?.node?.id }, + id: edge?.node?.id, display_label: { value: edge?.node?.display_label }, action: { value: edge?.node?.action?.value }, decision: { @@ -94,6 +94,7 @@ function GlobalPermissions() { value: { edges: edge?.node?.roles?.edges }, }, identifier: { display: }, + __typename: edge.node.__typename, }, }; }); diff --git a/frontend/app/src/screens/role-management/object-permissions-form.tsx b/frontend/app/src/screens/role-management/object-permissions-form.tsx index 9d35ef97a1..4c0b7b9c2f 100644 --- a/frontend/app/src/screens/role-management/object-permissions-form.tsx +++ b/frontend/app/src/screens/role-management/object-permissions-form.tsx @@ -118,9 +118,15 @@ export const ObjectPermissionForm = ({ }, }); - toast(, { - toastId: "alert-success-object-permission-created", - }); + if (currentObject) { + toast(, { + toastId: "alert-success-object-permission-updated", + }); + } else { + toast(, { + toastId: "alert-success-object-permission-created", + }); + } if (onSuccess) await onSuccess(result?.data?.[`${OBJECT_PERMISSION_OBJECT}Create`]); if (onUpdateComplete) await onUpdateComplete(); diff --git a/frontend/app/tests/e2e/role-management/roles-crud.spec.ts b/frontend/app/tests/e2e/role-management/roles-crud.spec.ts new file mode 100644 index 0000000000..2b7feffbd0 --- /dev/null +++ b/frontend/app/tests/e2e/role-management/roles-crud.spec.ts @@ -0,0 +1,103 @@ +import { expect, test } from "@playwright/test"; +import { ACCOUNT_STATE_PATH } from "../../constants"; + +test.describe("Role management - Roles CRUD", () => { + test.use({ storageState: ACCOUNT_STATE_PATH.ADMIN }); + test.describe.configure({ mode: "serial" }); + + test("should create a role ", async ({ page }) => { + await test.step("access main view", async () => { + await page.goto("/role-management/roles"); + }); + + await test.step("create role", async () => { + await expect(page.getByText("Retrieving roles...")).not.toBeVisible(); + await page.getByRole("button", { name: "Create Account role" }).click(); + await page.getByLabel("Name *").click(); + await page.getByLabel("Name *").fill("test role"); + await page.getByLabel("Groups").click(); + await page.getByTestId("side-panel-container").getByText("Infrahub Users").click(); + await page.getByLabel("Groups").click(); + await page.getByTestId("side-panel-container").getByLabel("Permissions").click(); + await page + .getByTestId("side-panel-container") + .getByText("global:super_admin:allow_all") + .first() + .click(); + await page + .getByTestId("side-panel-container") + .getByText("global:manage_repositories:") + .click(); + await page.getByTestId("side-panel-container").getByLabel("Permissions").click(); + await page.getByRole("button", { name: "Create" }).click(); + await expect(page.getByText("Role created!")).toBeVisible(); + }); + + await test.step("verify role creation", async () => { + await expect(page.getByRole("cell", { name: "test role" })).toBeVisible(); + await expect( + page + .getByRole("cell", { + name: "global:super_admin:allow_all global:manage_repositories:allow_all", + }) + .locator("div") + .first() + ).toBeVisible(); + }); + }); + + test("should update a role ", async ({ page }) => { + await test.step("access main view", async () => { + await page.goto("/role-management/roles"); + }); + + await test.step("update role", async () => { + await page + .getByRole("row", { name: "test role Infrahub Users" }) + .getByTestId("actions-row-button") + .click(); + await page.getByTestId("update-row-button").click(); + await page.getByLabel("Name *").click(); + await page.getByLabel("Name *").fill("test role 2"); + await page.getByLabel("Groups").click(); + await page.getByLabel("", { exact: true }).getByText("Infrahub Users").click(); + await page.getByTestId("side-panel-container").getByText("Super Administrators").click(); + await page.getByLabel("Groups").click(); + await page.getByTestId("side-panel-container").getByLabel("Permissions").click(); + await page + .getByTestId("side-panel-container") + .getByText("global:manage_schema:allow_all") + .click(); + await page.getByTestId("side-panel-container").getByLabel("Permissions").click(); + await page.getByRole("button", { name: "Update" }).click(); + await expect(page.getByText("Role updated!")).toBeVisible(); + }); + + await test.step("verify role update", async () => { + await expect(page.getByText("test role 2")).toBeVisible(); + await expect(page.getByText("Super Administrators").nth(1)).toBeVisible(); + }); + }); + + test("should delete a role ", async ({ page }) => { + await test.step("access main view", async () => { + await page.goto("/role-management/roles"); + }); + + await test.step("delete role", async () => { + await page + .getByRole("row", { name: "test role 2" }) + .getByTestId("actions-row-button") + .click(); + await page.getByTestId("delete-row-button").click(); + await page.getByTestId("modal-delete-confirm").click(); + await expect(page.getByText("Are you sure you want to remove")).not.toBeVisible(); + await expect(page.getByText("Object test role 2 deleted")).toBeVisible(); + }); + + await test.step("verify role delete", async () => { + await expect(page.getByTestId("objects-search-input-loader")).not.toBeVisible(); + await expect(page.getByText("test role 2")).not.toBeVisible(); + }); + }); +});