Fleet UI: Users page disable checkboxes not meeting requirements (#44080)

This commit is contained in:
RachelElysia
2026-04-24 09:43:03 -04:00
committed by GitHub
parent ba78337e7a
commit ef490b70fc
6 changed files with 189 additions and 55 deletions
+2 -1
View File
@@ -83,8 +83,9 @@ export interface IMdmConfig {
macos_manual_agent_install: boolean | null;
require_all_software_macos: boolean | null;
lock_end_user_info: boolean | null;
enable_create_local_admin_account?: boolean;
};
macos_setup: {
macos_setup?: {
enable_managed_local_account?: boolean;
};
macos_migration: IMacOsMigrationSettings;
+2 -1
View File
@@ -67,8 +67,9 @@ export interface ITeam extends ITeamSummary {
macos_manual_agent_install: boolean | null;
require_all_software_macos: boolean | null;
lock_end_user_info: boolean | null;
enable_create_local_admin_account?: boolean;
};
macos_setup: {
macos_setup?: {
enable_managed_local_account?: boolean;
};
windows_updates: {
@@ -9,7 +9,7 @@ import { ITeamConfig } from "interfaces/team";
import SectionHeader from "components/SectionHeader/SectionHeader";
import Spinner from "components/Spinner";
import GenericMsgWithNavButton from "components/GenericMsgWithNavButton";
import CustomLink from "components/CustomLink";
import { LEARN_MORE_ABOUT_BASE_LINK } from "utilities/constants";
@@ -30,11 +30,15 @@ const getEnabledManagedLocalAccount = (
if (currentTeamId === 0) {
return (
globalConfig?.mdm?.macos_setup?.enable_managed_local_account ?? false
globalConfig?.mdm?.setup_experience?.enable_create_local_admin_account ??
false
);
}
return teamConfig?.mdm?.macos_setup?.enable_managed_local_account ?? false;
return (
teamConfig?.mdm?.setup_experience?.enable_create_local_admin_account ??
false
);
};
const getEnabledEndUserAuth = (
@@ -129,22 +133,13 @@ const Users = ({ currentTeamId, router }: ISetupExperienceCardProps) => {
const mdmConfig = globalConfig.mdm;
return (
<SetupExperienceContentContainer>
{!isIdPConfigured(mdmConfig) ? (
<GenericMsgWithNavButton
header="Require end user authentication during setup"
info="Connect Fleet to your identity provider (IdP) to get started."
buttonText="Connect"
router={router}
path={PATHS.ADMIN_INTEGRATIONS_SSO_END_USERS}
/>
) : (
<UsersForm
currentTeamId={currentTeamId}
defaultIsEndUserAuthEnabled={defaultIsEndUserAuthEnabled}
defaultLockEndUserInfo={defaultLockEndUserInfo}
defaultEnableManagedLocalAccount={defaultEnableManagedLocalAccount}
/>
)}
<UsersForm
currentTeamId={currentTeamId}
defaultIsEndUserAuthEnabled={defaultIsEndUserAuthEnabled}
defaultLockEndUserInfo={defaultLockEndUserInfo}
defaultEnableManagedLocalAccount={defaultEnableManagedLocalAccount}
isIdPConfigured={isIdPConfigured(mdmConfig)}
/>
</SetupExperienceContentContainer>
);
};
@@ -10,12 +10,27 @@ describe("UsersForm", () => {
defaultIsEndUserAuthEnabled: false,
defaultLockEndUserInfo: false,
defaultEnableManagedLocalAccount: false,
isIdPConfigured: true,
};
const render = createCustomRenderer({
withBackendMock: true,
});
const renderWithMdmEnabled = createCustomRenderer({
withBackendMock: true,
context: {
app: { isMacMdmEnabledAndConfigured: true },
},
});
const renderWithMdmDisabled = createCustomRenderer({
withBackendMock: true,
context: {
app: { isMacMdmEnabledAndConfigured: false },
},
});
it("renders the end user authentication and managed local account checkboxes", () => {
render(<UsersForm {...defaultProps} />);
expect(screen.getByText("End user authentication")).toBeInTheDocument();
@@ -83,4 +98,71 @@ describe("UsersForm", () => {
const saveButtons = screen.getAllByRole("button", { name: "Save" });
expect(saveButtons).toHaveLength(1);
});
describe("disabled states", () => {
it("disables end user authentication checkbox when IdP is not configured", () => {
render(<UsersForm {...defaultProps} isIdPConfigured={false} />);
expect(
screen.getByRole("checkbox", { name: "End user authentication" })
).toHaveAttribute("aria-disabled", "true");
});
it("enables end user authentication checkbox when IdP is configured", () => {
render(<UsersForm {...defaultProps} isIdPConfigured />);
expect(
screen.getByRole("checkbox", { name: "End user authentication" })
).toHaveAttribute("aria-disabled", "false");
});
it("disables lock end user info when IdP is not configured", () => {
render(
<UsersForm
{...defaultProps}
isIdPConfigured={false}
defaultIsEndUserAuthEnabled
/>
);
expect(
screen.getByRole("checkbox", { name: "Lock end user info" })
).toHaveAttribute("aria-disabled", "true");
});
it("does not allow toggling end user auth when IdP is not configured", async () => {
const { user } = render(
<UsersForm {...defaultProps} isIdPConfigured={false} />
);
const checkbox = screen.getByRole("checkbox", {
name: "End user authentication",
});
await user.click(checkbox);
expect(checkbox).not.toBeChecked();
});
it("disables managed local account checkbox when Apple MDM is not configured", () => {
renderWithMdmDisabled(<UsersForm {...defaultProps} />);
expect(
screen.getByRole("checkbox", { name: "Managed local account" })
).toHaveAttribute("aria-disabled", "true");
});
it("enables managed local account checkbox when Apple MDM is configured", () => {
renderWithMdmEnabled(<UsersForm {...defaultProps} />);
expect(
screen.getByRole("checkbox", { name: "Managed local account" })
).toHaveAttribute("aria-disabled", "false");
});
it("does not allow toggling managed local account when Apple MDM is not configured", async () => {
const { user } = renderWithMdmDisabled(<UsersForm {...defaultProps} />);
const checkbox = screen.getByRole("checkbox", {
name: "Managed local account",
});
await user.click(checkbox);
expect(checkbox).not.toBeChecked();
});
});
});
@@ -18,6 +18,7 @@ interface IUsersFormProps {
defaultIsEndUserAuthEnabled: boolean;
defaultLockEndUserInfo: boolean;
defaultEnableManagedLocalAccount: boolean;
isIdPConfigured: boolean;
}
const UsersForm = ({
@@ -25,10 +26,11 @@ const UsersForm = ({
defaultIsEndUserAuthEnabled,
defaultLockEndUserInfo,
defaultEnableManagedLocalAccount,
isIdPConfigured,
}: IUsersFormProps) => {
const { renderFlash } = useContext(NotificationContext);
const gitOpsModeEnabled = useContext(AppContext).config?.gitops
.gitops_mode_enabled;
const { config, isMacMdmEnabledAndConfigured } = useContext(AppContext);
const gitOpsModeEnabled = config?.gitops.gitops_mode_enabled;
const [isEndUserAuthEnabled, setEndUserAuthEnabled] = useState(
defaultIsEndUserAuthEnabled
@@ -68,7 +70,8 @@ const UsersForm = ({
setEnableManagedLocalAccount(newCheckVal);
};
const onClickSave = async () => {
const onClickSave = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsUpdating(true);
const canLockEndUserInfo = isEndUserAuthEnabled && lockEndUserInfo;
@@ -91,27 +94,49 @@ const UsersForm = ({
return (
<div className={baseClass}>
<form onSubmit={onClickSave}>
<Checkbox
disabled={gitOpsModeEnabled}
value={isEndUserAuthEnabled}
onChange={onToggleEndUserAuth}
helpText={
<span>
End users are required to authenticate with your{" "}
<CustomLink
url={PATHS.ADMIN_INTEGRATIONS_SSO_END_USERS}
text="identity provider (IdP)"
/>{" "}
when setting up new hosts.
</span>
<TooltipWrapper
tipContent={
!isIdPConfigured ? (
<span>
To enable, first connect Fleet to
<br />
your{" "}
<CustomLink
url={PATHS.ADMIN_INTEGRATIONS_SSO_END_USERS}
text="identity provider (IdP)"
variant="tooltip-link"
/>
.
</span>
) : undefined
}
disableTooltip={isIdPConfigured}
underline={false}
position="left"
showArrow
>
End user authentication
</Checkbox>
<Checkbox
disabled={gitOpsModeEnabled || !isIdPConfigured}
value={isEndUserAuthEnabled}
onChange={onToggleEndUserAuth}
helpText={
<span>
End users are required to authenticate with your{" "}
<CustomLink
url={PATHS.ADMIN_INTEGRATIONS_SSO_END_USERS}
text="identity provider (IdP)"
/>{" "}
when setting up new hosts.
</span>
}
>
End user authentication
</Checkbox>
</TooltipWrapper>
{isEndUserAuthEnabled && (
<div className={`${baseClass}__advanced-options`}>
<Checkbox
disabled={gitOpsModeEnabled}
disabled={gitOpsModeEnabled || !isIdPConfigured}
onChange={onChangeLockEndUserInfo}
value={lockEndUserInfo}
>
@@ -133,22 +158,50 @@ const UsersForm = ({
</Checkbox>
</div>
)}
<Checkbox
disabled={gitOpsModeEnabled}
value={enableManagedLocalAccount}
onChange={onToggleManagedLocalAccount}
helpText={
<span>
Fleet generates a user (_fleetadmin) and unique password for each
host, accessible in <b>Host details</b> &gt;{" "}
<b>Show managed account</b>.
</span>
<TooltipWrapper
tipContent={
!isMacMdmEnabledAndConfigured ? (
<span>
To enable, first turn on{" "}
<CustomLink
url={PATHS.ADMIN_INTEGRATIONS_MDM_APPLE}
text="Apple MDM"
variant="tooltip-link"
/>
.
</span>
) : undefined
}
disableTooltip={!!isMacMdmEnabledAndConfigured}
underline={false}
position="left"
showArrow
>
<TooltipWrapper tipContent="Creates a hidden managed local admin account for remote troubleshooting on macOS hosts.">
Managed local account
</TooltipWrapper>
</Checkbox>
<Checkbox
disabled={gitOpsModeEnabled || !isMacMdmEnabledAndConfigured}
value={enableManagedLocalAccount}
onChange={onToggleManagedLocalAccount}
helpText={
<span>
Fleet generates a user (_fleetadmin) and unique password for
each host, accessible in <b>Host details</b> &gt;{" "}
<b>Show managed account</b>.
</span>
}
>
<TooltipWrapper
tipContent={
<>
Creates a hidden managed local admin account for
<br />
remote troubleshooting on macOS hosts.
</>
}
>
Managed local account
</TooltipWrapper>
</Checkbox>
</TooltipWrapper>
<GitOpsModeTooltipWrapper
renderChildren={(disableChildren) => (
<Button
@@ -340,7 +340,9 @@ const canShowManagedAccount = (config: IHostActionConfigOptions) => {
if (hostPlatform !== "darwin") return false;
if (!isConnectedToFleetMdm) return false;
if (!isAutomaticDeviceEnrollment(hostMdmEnrollmentStatus)) return false;
if (!isManagedLocalAccountEnabled) return false;
if (!isManagedLocalAccountEnabled && !config.managedAccountStatus) {
return false;
}
return isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer;
};