diff --git a/cypress/integration/users_test.spec.ts b/cypress/integration/users_test.spec.ts index 4a3bc7079f..7a9442050a 100644 --- a/cypress/integration/users_test.spec.ts +++ b/cypress/integration/users_test.spec.ts @@ -21,6 +21,8 @@ describe("Users test", () => { }); it("Go to create User page", () => { + cy.wait(100); + createUserPage.goToCreateUser(); cy.url().should("include", "users/add-user"); @@ -31,9 +33,12 @@ describe("Users test", () => { it("Create user test", function () { itemId += "_" + (Math.random() + 1).toString(36).substring(7); - + // Create + cy.wait(100); + createUserPage.goToCreateUser(); + createUserPage.fillRealmRoleData(itemId).save(); masthead.checkNotificationMessage("The user has been created"); diff --git a/cypress/support/pages/admin_console/manage/users/CreateUserPage.ts b/cypress/support/pages/admin_console/manage/users/CreateUserPage.ts index e5e477af52..451027f911 100644 --- a/cypress/support/pages/admin_console/manage/users/CreateUserPage.ts +++ b/cypress/support/pages/admin_console/manage/users/CreateUserPage.ts @@ -1,11 +1,17 @@ export default class CreateUserPage { usernameInput: string; + usersEmptyState: string; + emptyStateCreateUserBtn: string; + searchPgCreateUserBtn: string; saveBtn: string; cancelBtn: string; constructor() { this.usernameInput = "#kc-username"; + this.usersEmptyState = "[data-testid=empty-state]"; + this.emptyStateCreateUserBtn = "[data-testid=empty-primary-action]"; + this.searchPgCreateUserBtn = "[data-testid=create-new-user]"; this.saveBtn = "[data-testid=create-user]"; this.cancelBtn = "[data-testid=cancel-create-user]"; } @@ -22,7 +28,16 @@ export default class CreateUserPage { } goToCreateUser() { - cy.get("[data-testid=add-user").click(); + cy.wait(100); + cy.get("body").then((body) => { + if (body.find(this.usersEmptyState).length > 0) { + cy.get(this.emptyStateCreateUserBtn).click(); + } else if (body.find("[data-testid=search-users-title]").length > 0) { + cy.get(this.searchPgCreateUserBtn).click(); + } else { + cy.get("[data-testid=add-user]").click(); + } + }); return this; } diff --git a/src/components/list-empty-state/ListEmptyState.tsx b/src/components/list-empty-state/ListEmptyState.tsx index cc095f1c05..6ffc94b407 100644 --- a/src/components/list-empty-state/ListEmptyState.tsx +++ b/src/components/list-empty-state/ListEmptyState.tsx @@ -38,7 +38,7 @@ export const ListEmptyState = ({ }: ListEmptyStateProps) => { return ( <> - + {hasIcon && isSearchVariant ? ( ) : ( diff --git a/src/user/SearchUser.tsx b/src/user/SearchUser.tsx index b47d367e32..5ba8ced177 100644 --- a/src/user/SearchUser.tsx +++ b/src/user/SearchUser.tsx @@ -28,7 +28,7 @@ export const SearchUser = ({ onSearch }: SearchUserProps) => { return ( - + <Title data-testid="search-users-title" headingLevel="h4" size="lg"> {t("startBySearchingAUser")} @@ -50,7 +50,7 @@ export const SearchUser = ({ onSearch }: SearchUserProps) => { - diff --git a/src/user/UserForm.tsx b/src/user/UserForm.tsx index 128d778cbd..615da7db3d 100644 --- a/src/user/UserForm.tsx +++ b/src/user/UserForm.tsx @@ -10,7 +10,7 @@ import { } from "@patternfly/react-core"; import { useTranslation } from "react-i18next"; import { Controller, UseFormMethods } from "react-hook-form"; -import { useHistory, useRouteMatch } from "react-router-dom"; +import { useHistory } from "react-router-dom"; import { FormAccess } from "../components/form-access/FormAccess"; import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation"; import { HelpItem } from "../components/help-enabler/HelpItem"; @@ -27,7 +27,6 @@ export const UserForm = ({ }: UserFormProps) => { const { t } = useTranslation("users"); const { realm } = useRealm(); - const { url } = useRouteMatch(); const [ isRequiredUserActionsDropdownOpen, @@ -38,6 +37,8 @@ export const UserForm = ({ const watchUsernameInput = watch("username"); + const emailRegexPattern = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + const requiredUserActionsOptions = [ {t("configureOTP")} @@ -61,8 +62,6 @@ export const UserForm = ({ setRequiredUserActionsDropdownOpen(false); }; - const goToCreate = () => history.push(`${url}/add-user`); - return ( - diff --git a/src/user/UsersSection.tsx b/src/user/UsersSection.tsx index 7194db3305..05e8221058 100644 --- a/src/user/UsersSection.tsx +++ b/src/user/UsersSection.tsx @@ -166,7 +166,7 @@ export const UsersSection = () => { <> - + {!listUsers && !initialSearch && ( { diff --git a/src/user/UsersTabs.tsx b/src/user/UsersTabs.tsx index 35839710f6..d37b36f351 100644 --- a/src/user/UsersTabs.tsx +++ b/src/user/UsersTabs.tsx @@ -8,18 +8,30 @@ import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation"; import { UserForm } from "./UserForm"; import { useAlerts } from "../components/alert/Alerts"; import { useAdminClient } from "../context/auth/AdminClient"; +import { useHistory, useRouteMatch } from "react-router-dom"; export const UsersTabs = () => { const { t } = useTranslation("roles"); - const form = useForm({ mode: "onChange" }); const { addAlert } = useAlerts(); + const { url } = useRouteMatch(); + const history = useHistory(); + const adminClient = useAdminClient(); + const form = useForm({ mode: "onChange" }); const save = async (user: UserRepresentation) => { try { - await adminClient.users.create({ username: user!.username }); - + await adminClient.users.create({ + username: user!.username, + email: user!.email, + emailVerified: user!.emailVerified, + firstName: user!.firstName, + lastName: user!.lastName, + enabled: user!.enabled, + requiredActions: user!.requiredActions, + }); addAlert(t("users:userCreated"), AlertVariant.success); + history.push(url.substr(0, url.lastIndexOf("/"))); } catch (error) { addAlert( t("users:userCreateError", { diff --git a/src/user/messages.json b/src/user/messages.json index dd069cf42c..8b37d0d01a 100644 --- a/src/user/messages.json +++ b/src/user/messages.json @@ -17,6 +17,7 @@ "disabled": "Disabled", "disabledHelpText": "A disabled user cannot log in.", "emailVerifiedHelpText": "Has the user's email been verified?", + "emailInvalid": "You must enter a valid email.", "temporaryDisabled": "Temporarily disabled", "notVerified": "Not verified", "requiredUserActions": "Required user actions",