fleet/frontend/pages/hosts/details/HostDetailsPage/modals/ClearPasscodeModal/ClearPasscodeModal.tsx
Magnus Jensen bc32339526
Clear passcode frontend (#43084)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #42369 

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information. **Done in backend task for whole story**

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] QA'd all new/changed functionality manually


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added "Clear passcode" action for iOS and iPad hosts in the host
actions menu, accessible only to Premium tier users with appropriate
permissions.
  * Added confirmation modal for clearing device passcodes.
* Passcode clearing activity now appears in the activity feed with actor
information.
* Action is conditionally disabled during specific device states (Lost
Mode, pending wipe) with contextual tooltips.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-07 16:36:03 -05:00

78 lines
1.9 KiB
TypeScript

import React, { useContext } from "react";
import { NotificationContext } from "context/notification";
import hostAPI from "services/entities/hosts";
import Modal from "components/Modal";
import Button from "components/buttons/Button";
const baseClass = "clear-passcode-modal";
interface IClearPasscodeModalProps {
id: number;
onExit: () => void;
}
const ClearPasscodeModal = ({ id, onExit }: IClearPasscodeModalProps) => {
const { renderFlash } = useContext(NotificationContext);
const [isClearingPasscode, setIsClearingPasscode] = React.useState(false);
const onClearPasscode = async () => {
setIsClearingPasscode(true);
try {
await hostAPI.clearPasscode(id);
renderFlash(
"success",
"Successfully sent request to clear passcode on this host."
);
} catch (e) {
renderFlash(
"error",
"Couldn't send request to clear passcode on this host. Please try again."
);
} finally {
onExit();
setIsClearingPasscode(false);
}
};
const renderModalContent = () => {
return (
<p>
This will remove the current passcode and allow anyone with physical
access to unlock the host.
</p>
);
};
const renderModalButtons = () => {
return (
<>
<Button
type="button"
onClick={onClearPasscode}
className="clear-passcode-loading"
variant="alert"
isLoading={isClearingPasscode}
>
Clear Passcode
</Button>
<Button onClick={onExit} variant="inverse-alert">
Cancel
</Button>
</>
);
};
return (
<Modal className={baseClass} title="Clear passcode" onExit={onExit}>
<div className={`${baseClass}__modal-content`}>
{renderModalContent()}
</div>
<div className="modal-cta-wrap">{renderModalButtons()}</div>
</Modal>
);
};
export default ClearPasscodeModal;