Unify save-buttons in admin-ui (#30119)

* #30118 Unify save-buttons in admin-ui

Signed-off-by: Andreas Blaettlinger <bln1imb@bosch.com>

* #30118 Unify save-buttons in admin-ui

Signed-off-by: Andreas Blaettlinger <bln1imb@bosch.com>

* Introduced props for naming the buttons in FixedButtonGroup

Signed-off-by: Andreas Blaettlinger <bln1imb@bosch.com>

---------

Signed-off-by: Andreas Blaettlinger <bln1imb@bosch.com>
This commit is contained in:
Andreas Blättlinger 2024-06-18 13:00:45 +02:00 committed by GitHub
parent 5ad3abaa96
commit 2a88d01e5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 45 additions and 85 deletions

View file

@ -1,5 +1,5 @@
export default class AttributesTab {
#saveAttributeBtn = "save-attributes";
#saveAttributeBtn = "attributes-save";
#attributesTab = "attributes";
#emptyState = "attributes-empty-state";
#addAttributeBtn: string;

View file

@ -31,7 +31,7 @@ export default class KeyValueInput {
}
save() {
cy.findByTestId("save-attributes").click();
cy.findByTestId("attributes-save").click();
return this;
}

View file

@ -11,8 +11,8 @@ enum RealmSettingsTab {
const expect = chai.expect;
export default class RealmSettingsPage extends CommonPage {
generalSaveBtn = "general-tab-save";
generalRevertBtn = "general-tab-revert";
generalSaveBtn = "realmSettingsGeneralTab-save";
generalRevertBtn = "realmSettingsGeneralTab-revert";
themesSaveBtn = "themes-tab-save";
loginTab = "rs-login-tab";
emailTab = "rs-email-tab";

View file

@ -21,9 +21,9 @@ export default class CreateUserPage {
this.addUserBtn = "add-user";
this.joinGroupsBtn = "join-groups-button";
this.joinBtn = "join-button";
this.createBtn = "create-user";
this.saveBtn = "save-user";
this.cancelBtn = "cancel-create-user";
this.createBtn = "user-creation-save";
this.saveBtn = "user-creation-save";
this.cancelBtn = "user-creation-revert";
}
//#region General Settings

View file

@ -19,7 +19,7 @@ export default class UserDetailsPage extends PageObject {
constructor() {
super();
this.saveBtn = "save-user";
this.saveBtn = "user-creation-save";
this.cancelBtn = "cancel-create-user";
this.emailInput = "email";
this.emailValue = () => "example" + "_" + uuid() + "@example.com";

View file

@ -7,7 +7,9 @@ import style from "./fixed-buttons.module.css";
type FixedButtonGroupProps = ActionGroupProps & {
name: string;
save?: () => void;
saveText?: string;
reset?: () => void;
resetText?: string;
isSubmit?: boolean;
isActive?: boolean;
};
@ -15,7 +17,9 @@ type FixedButtonGroupProps = ActionGroupProps & {
export const FixedButtonsGroup = ({
name,
save,
saveText,
reset,
resetText,
isSubmit = false,
isActive = true,
children,
@ -31,7 +35,7 @@ export const FixedButtonsGroup = ({
onClick={() => save?.()}
type={isSubmit ? "submit" : "button"}
>
{t("save")}
{!saveText ? t("save") : saveText}
</Button>
)}
{reset && (
@ -41,7 +45,7 @@ export const FixedButtonsGroup = ({
variant="link"
onClick={() => reset()}
>
{t("revert")}
{!resetText ? t("revert") : resetText}
</Button>
)}
{children}

View file

@ -1,11 +1,10 @@
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
import { ActionGroup, Button } from "@patternfly/react-core";
import { FormProvider, UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { FormAccess } from "../form/FormAccess";
import type { KeyValueType } from "./key-value-convert";
import { KeyValueInput } from "./KeyValueInput";
import { FixedButtonsGroup } from "../form/FixedButtonGroup";
export type AttributeForm = Omit<RoleRepresentation, "attributes"> & {
attributes?: KeyValueType[];
@ -28,12 +27,8 @@ export const AttributesForm = ({
name = "attributes",
isDisabled = false,
}: AttributesFormProps) => {
const { t } = useTranslation();
const noSaveCancelButtons = !save && !reset;
const {
formState: { isDirty },
handleSubmit,
} = form;
const { handleSubmit } = form;
return (
<FormAccess
@ -45,19 +40,7 @@ export const AttributesForm = ({
<KeyValueInput name={name} isDisabled={isDisabled} />
</FormProvider>
{!noSaveCancelButtons && (
<ActionGroup className="kc-attributes__action-group">
<Button
data-testid="save-attributes"
variant="primary"
type="submit"
isDisabled={!isDirty}
>
{t("save")}
</Button>
<Button onClick={reset} variant="link" isDisabled={!isDirty}>
{t("revert")}
</Button>
</ActionGroup>
<FixedButtonsGroup name="attributes" reset={reset} isActive isSubmit />
)}
</FormAccess>
);

View file

@ -4,8 +4,6 @@ import {
UserProfileConfig,
} from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata";
import {
ActionGroup,
Button,
ClipboardCopy,
FormGroup,
PageSection,
@ -27,6 +25,7 @@ import { FormattedLink } from "../components/external-link/FormattedLink";
import { FormAccess } from "../components/form/FormAccess";
import { KeyValueInput } from "../components/key-value-form/KeyValueInput";
import { KeycloakSpinner } from "../components/keycloak-spinner/KeycloakSpinner";
import { FixedButtonsGroup } from "../components/form/FixedButtonGroup";
import { useRealm } from "../context/realm-context/RealmContext";
import {
addTrailingSlash,
@ -105,7 +104,7 @@ function RealmSettingsGeneralTabForm({
control,
handleSubmit,
setValue,
formState: { isDirty, errors },
formState: { errors },
} = form;
const isFeatureEnabled = useIsFeatureEnabled();
const isOrganizationsEnabled = isFeatureEnabled(Feature.Organizations);
@ -266,23 +265,12 @@ function RealmSettingsGeneralTabForm({
</StackItem>
</Stack>
</FormGroup>
<ActionGroup>
<Button
variant="primary"
type="submit"
data-testid="general-tab-save"
isDisabled={!isDirty}
>
{t("save")}
</Button>
<Button
data-testid="general-tab-revert"
variant="link"
onClick={setupForm}
>
{t("revert")}
</Button>
</ActionGroup>
<FixedButtonsGroup
name="realmSettingsGeneralTab"
reset={setupForm}
isActive
isSubmit
/>
</FormAccess>
</FormProvider>
</PageSection>

View file

@ -4,14 +4,12 @@ import { UserProfileMetadata } from "@keycloak/keycloak-admin-client/lib/defs/us
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import {
FormErrorText,
FormSubmitButton,
HelpItem,
SwitchControl,
TextControl,
UserProfileFields,
} from "@keycloak/keycloak-ui-shared";
import {
ActionGroup,
AlertVariant,
Button,
Chip,
@ -26,7 +24,6 @@ import { TFunction } from "i18next";
import { useEffect, useState } from "react";
import { Controller, FormProvider, UseFormReturn } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { useAdminClient } from "../admin-client";
import { DefaultSwitchControl } from "../components/SwitchControl";
import { useAlerts } from "../components/alert/Alerts";
@ -39,7 +36,9 @@ import useFormatDate from "../utils/useFormatDate";
import { FederatedUserLink } from "./FederatedUserLink";
import { UserFormFields, toUserFormFields } from "./form-state";
import { toUsers } from "./routes/Users";
import { FixedButtonsGroup } from "../components/form/FixedButtonGroup";
import { RequiredActionMultiSelect } from "./user-credentials/RequiredActionMultiSelect";
import { useNavigate } from "react-router-dom";
export type BruteForced = {
isBruteForceProtected?: boolean;
@ -79,15 +78,15 @@ export const UserForm = ({
const { whoAmI } = useWhoAmI();
const currentLocale = whoAmI.getLocale();
const { handleSubmit, setValue, watch, control, reset, formState } = form;
const { handleSubmit, setValue, control, reset, formState } = form;
const { errors } = formState;
const watchUsernameInput = watch("username");
const [selectedGroups, setSelectedGroups] = useState<GroupRepresentation[]>(
[],
);
const [open, setOpen] = useState(false);
const [locked, setLocked] = useState(isLocked);
const navigate = useNavigate();
useEffect(() => {
setValue("requiredActions", user?.requiredActions || []);
@ -132,6 +131,14 @@ export const UserForm = ({
setOpen(!open);
};
const onFormReset = () => {
if (user?.id) {
reset(toUserFormFields(user));
} else {
navigate(toUsers({ realm: realm.realm! }));
}
};
return (
<FormAccess
isHorizontal
@ -327,37 +334,15 @@ export const UserForm = ({
)}
</FormGroup>
)}
<ActionGroup>
<FormSubmitButton
formState={formState}
data-testid={!user?.id ? "create-user" : "save-user"}
isDisabled={
!user?.id &&
!watchUsernameInput &&
realm.registrationEmailAsUsername === false
}
allowNonDirty
allowInvalid
>
{user?.id ? t("save") : t("create")}
</FormSubmitButton>
<Button
data-testid="cancel-create-user"
variant="link"
onClick={user?.id ? () => reset(toUserFormFields(user)) : undefined}
component={
!user?.id
? (props) => (
<Link {...props} to={toUsers({ realm: realm.realm! })} />
)
: undefined
}
>
{user?.id ? t("revert") : t("cancel")}
</Button>
</ActionGroup>
</FormProvider>
<FixedButtonsGroup
name="user-creation"
saveText={user?.id ? t("save") : t("create")}
reset={onFormReset}
resetText={user?.id ? t("revert") : t("cancel")}
isActive
isSubmit
/>
</FormAccess>
);
};