Easier-to-manage policy automations with continuous retry option - #46056
Conversation
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45145 Implemented changes for the details page. Figma: https://www.figma.com/design/QeOcex5LtuDYG9XrGnMFLZ/-42651-Easier-to-manage-policy-automations-with-continuous-retry-option-for-software-scripts?node-id=5324-2588&t=vaLDU8QQXQ7vUq1k-0 NOTE: decided to show the Automations section with an empty state (was a TODO in Figma): <img width="262" height="158" alt="Screenshot 2026-05-20 at 4 53 24 PM" src="https://github.com/user-attachments/assets/137e992c-ca6e-41e0-8fe4-8948e232561f" /> # Checklist for submitter - [ ] 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. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/17d6e3f4-8cf2-443f-b895-cb5e3e13e985
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #46056 +/- ##
==========================================
+ Coverage 66.85% 66.87% +0.01%
==========================================
Files 2809 2821 +12
Lines 223605 223907 +302
Branches 11482 11534 +52
==========================================
+ Hits 149498 149734 +236
- Misses 60537 60603 +66
Partials 13570 13570
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45145 (will do a follow-up PR for the changes in the Details page). # Checklist for submitter - [ ] 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. Will add a single file in the feature branch (policy-automations-continuous-retries) once done with all the changes. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/c141422e-151c-4f28-9ec5-30ce5cf38cd2
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45147 Implements the [Automations modal](https://www.figma.com/design/QeOcex5LtuDYG9XrGnMFLZ/-42651-Easier-to-manage-policy-automations-with-continuous-retry-option-for-software-scripts?node-id=5345-6017&t=U4xhTwwGzJ9osxYF-0). Note: I'll modify the filenames to reflect that they're forms and not modals anymore in a follow-up, so that the diff isn't too large (I'm referring to ConditionalAccessModal, CalendarEventsModal and OtherWorkflowsModal). ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually **Maintainer** doesn't see the `Automations` button at the top-right. (They can't enable/disable any of the global settings for `Calendar events`, `Webhooks/tickets`, or `Conditional access`.) <img width="1457" height="464" alt="Screenshot 2026-05-25 at 12 02 46 PM" src="https://github.com/user-attachments/assets/8d8febc7-712c-4d69-9da6-3bcdcb95366e" /> **Global admin** can enable/disable any of the settings for a particular fleet. <img width="1526" height="1181" alt="Screenshot 2026-05-25 at 12 03 10 PM" src="https://github.com/user-attachments/assets/0ba760e1-9b24-4b4f-9776-74b02e0d503b" /> **Global admin** can only enable/disable `Webhooks/tickets` for `All fleets`. <img width="1454" height="650" alt="Screenshot 2026-05-25 at 12 03 31 PM" src="https://github.com/user-attachments/assets/3f8b5f58-ac5c-419d-a5a1-9c612216fad8" /> **_Team_ admin** doesn't see links to sections they don't have access to. (*) <img width="833" height="279" alt="Screenshot 2026-05-25 at 12 11 45 PM" src="https://github.com/user-attachments/assets/176c9bee-fbe3-4054-a923-44827001b847" /> (*) They also don't have access to where the `Add integration` button links to -- this is shown when selecting `Tickets` but no integrations are configured. I haven't modified that section yet since I'm waiting for answers here: https://fleetdm.slack.com/archives/C084F4MKYSJ/p1779721815248149, but this can easily be a follow-up. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Automations modal now fully functional with policy automation configuration and management capabilities. * **Improvements** * Simplified calendar events and conditional access configuration UI for clearer workflows. * Updated permission logic for automations management features. * Enhanced visual styling for custom links and modal layouts. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/46023?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45148 (just the modal itself, Edit policy and Save policy modal changes will be follow-ups). Figma: https://www.figma.com/design/QeOcex5LtuDYG9XrGnMFLZ/-42651-Easier-to-manage-policy-automations-with-continuous-retry-option-for-software-scripts?node-id=5373-9851&t=U4xhTwwGzJ9osxYF-0 ## Testing - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/5a457bb2-b3fe-4761-a8f2-21921631ff59 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Implemented a fully functional policy automations management modal with support for multiple automation types, including ticket/webhook integration, software installation, script execution, calendar events, conditional access, and continuous automations * Added dynamic software and script selection with platform-specific filtering for policy configurations <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/46254?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…rited policies (#46271) **Related issue:** #45148 and #45145 ## Summary Stacked on top of the Manage automations modal PR (#46254). Two follow-up tweaks: - **Open the modal from the empty ("---") automations cell.** Policies with no automations configured were previously a non-interactive cell. Now, for users who can edit, the empty cell is clickable. - **Handle inherited policies opened from a fleet's list.** An inherited policy has `team_id === null` even when viewed from within a specific fleet. It's now treated as global (only the webhook/ticket row, no continuous-retry option) and the modal is routed to the **global** config for its automations, instead of inferring "global" from the selected-team view. ## Testing - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/9a927373-e1d2-4326-92cc-a97f26d85962 https://github.com/user-attachments/assets/9ff9c393-56c7-4631-9052-477a8736af7a
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45148 (Edit flow) ## Testing - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/a25446ca-8c31-40d4-8ed0-d8d9cb612f97 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Refactor** * Reorganized the automation management modal to use form-based submission * Separated patch automation prompt into a dedicated component * Restructured automation field management for improved component reusability * **Tests** * Added comprehensive test coverage for automation components and call-to-action flows <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/46326?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45148 (Save policy modal) ## Testing - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/3306ba19-f02d-4874-8cc9-17782e63e1c8
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45151 ## Testing - [x] QA'd all new/changed functionality manually https://github.com/user-attachments/assets/f69aad05-69c9-47be-943a-aca571a9bf12
|
Had some conflicts w/ main because of these commits which introduced a useEffect to automatically open the old Manage Automations modals after a search in the new command palette UI:
Since we now have:
We'd need to think of how to route users to keep the existing functionality. (Or just redirect to Policies page.) Screen.Recording.2026-06-01.at.11.37.30.AM.mov |
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
There was a problem hiding this comment.
Pull request overview
Refactors the policies UI to consolidate per-policy and per-team automation management. The previous per-automation modals (OtherWorkflows, InstallSoftware, RunScript, CalendarEvents, ConditionalAccess) on the Manage Policies page are replaced by a unified AutomationsModal (team-level) and a per-row ManageAutomationsModal (policy-level). A new shared PolicyAutomationsFields form drives both the per-policy editor and the SaveNewPolicy modal, and a new continuous_automations_enabled field lets admins re-run script/software automations on every failure. Read-only summaries are extracted into PolicyAutomationsList and PatchAutomationCta.
Changes:
- Replace dropdown + per-modal flow on Manage Policies with a single team-level Automations modal and a row-level "Manage automations" modal driven by a shared
PolicyAutomationsFieldsform. - Add
continuous_automations_enabledtoIPolicy/IPolicyFormDataand the team_policies create/update payloads, surfaced as a "Continuous software & script automations" checkbox. - Refactor the automations cell/list rendering: new
getAutomationsForPolicy,getTicketOrWebhookInfohelpers, redesigned cell with icons + edit affordance, and a reusablePolicyAutomationsListsummary.
Reviewed changes
Copilot reviewed 68 out of 77 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/services/entities/team_policies.ts | Forwards continuous_automations_enabled in create/update payloads. |
| frontend/pages/policies/ManagePoliciesPage/ManagePoliciesPage.tsx | Replaces dropdown + 5 modals with unified Automations / ManageAutomations modals and new permission gate. |
| frontend/pages/policies/ManagePoliciesPage/helpers.tsx | Replaces getAutomationTypesString with structured getAutomationsForPolicy. |
| frontend/pages/policies/ManagePoliciesPage/helpers.tests.tsx | Updates tests for new helper shape and webhook/ticket labels. |
| frontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/PoliciesTableConfig.tsx | New AutomationsCell with icons, edit pencil, count tooltip; tooltip refactor. |
| frontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/PoliciesTable.tsx | Threads otherAutomationType and onOpenManageAutomationsModal props. |
| frontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/PoliciesTable.tests.tsx | Updates expectation to "2 automations". |
| frontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/_styles.scss | New styles for automations cell. |
| frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/* | Removed (moved into AutomationsModal subtree). |
| frontend/pages/policies/ManagePoliciesPage/components/ManageAutomationsModal/* | New per-policy automations modal using PolicyAutomationsFields. |
| frontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/* | Removed (replaced inside AutomationsModal). |
| frontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/* | Removed (replaced inside AutomationsModal). |
| frontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/* | New unified team-level automations modal, with sub-modals for Other/Calendar/ConditionalAccess and a shared IAutomationFormHandle ref protocol. |
| frontend/pages/policies/ManagePoliciesPage/_styles.scss | Drops dropdown styles, adds automations button styles. |
| frontend/pages/policies/hooks/useUpdatePolicyAutomations.ts | New shared mutation for per-policy automation + webhook membership. |
| frontend/pages/policies/hooks/index.ts | Re-exports the hook. |
| frontend/pages/policies/helpers.ts | New getTicketOrWebhookInfo and label helpers. |
| frontend/pages/policies/edit/screens/QueryEditor.tsx | Allows onCreatePolicy to chain a post-create automations save. |
| frontend/pages/policies/edit/EditPolicyPage.tsx | Removes now-unused team config fetch / currentAutomatedPolicies plumbing. |
| frontend/pages/policies/edit/components/SaveNewPolicyModal/* | Adds Automations section using shared fields and post-create save closure. |
| frontend/pages/policies/edit/components/PolicyForm/* | Integrates new PolicyAutomationsFields and PatchAutomationCta; chains automations save after policy update. |
| frontend/pages/policies/edit/components/PolicyAutomations/* | Removed (split into PolicyAutomationsList and PatchAutomationCta). |
| frontend/pages/policies/details/PolicyDetailsPage/PolicyDetailsPage.tsx | Uses new PolicyAutomationsList + PatchAutomationCta. |
| frontend/pages/policies/components/PolicyAutomationsList/* | New shared read-only automations summary with continuous-mode footer text. |
| frontend/pages/policies/components/PolicyAutomationsFields/* | New shared automations form (rows + continuous checkbox) used by create/edit/manage flows. |
| frontend/pages/policies/components/PatchAutomationCta/* | Extracted patch-policy CTA card from old PolicyAutomations. |
| frontend/pages/policies/components/index.ts | Barrel for new shared components. |
| frontend/interfaces/policy.ts | Adds OtherAutomationType, TicketOrWebhookState, and continuous_automations_enabled. |
| frontend/components/TableContainer/DataTable/_styles.scss | Minor radius constant refactor; removes duplicate corner rule. |
| frontend/components/CustomLink/_styles.scss | Replaces mixin with inline gradient underline supporting multiline links. |
| changes/42651-policy-automations-continuous-retry | Changelog entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** -1 = "All teams" sentinel from useTeamIdParam; otherwise team ID (0 for "No team"). */ | ||
| isAllTeamsSelected: boolean; |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughThis pull request refactors policy automations to support a new "Continuous" retry option for script and software automations. The changes consolidate scattered automation modals across the manage policies page into reusable, composable components: a new Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tests.tsx (1)
464-472:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winNested
waitForwithoutawaitand missingawaitonuser.hover.The inner
waitFor(line 465) is not awaited, anduser.hoverreturns a promise that should be awaited. This pattern can cause flaky tests because the hover may not complete before assertions run.Proposed fix
- await waitFor(() => { - waitFor(() => { - user.hover(screen.getByRole("button", { name: "Run policy" })); - }); - - expect( - screen.getByText(/live reports are disabled/i) - ).toBeInTheDocument(); - }); + await user.hover(screen.getByRole("button", { name: "Run policy" })); + + await waitFor(() => { + expect( + screen.getByText(/live reports are disabled/i) + ).toBeInTheDocument(); + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tests.tsx` around lines 464 - 472, The test uses a nested waitFor and does not await user.hover, causing flakiness; replace the inner waitFor by awaiting user.hover(...) directly (await user.hover(screen.getByRole("button", { name: "Run policy" }))) and then await a single waitFor that asserts the notice is present (await waitFor(() => expect(screen.getByText(/live reports are disabled/i)).toBeInTheDocument())); update the PolicyForm.tests.tsx test to remove the nested waitFor and ensure both the hover and the assertion are awaited.
🧹 Nitpick comments (5)
frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tsx (1)
496-503: 💤 Low value
persistAutomationsis not awaited, allowing the handler to return early.The
persistAutomationscall fires-and-forgets the automations mutation. SincesaveAutomationsis from react-query'suseMutation, it runs asynchronously. The function returns (and for patch policies, exits viareturnat line 517) before automations are confirmed saved. This means:
- User could navigate away or interact before automations persist
- The
isSavingAutomationsloading state at line 858 might not fully cover the operation if the outer function completes firstIf the intent is fire-and-forget with
isSavingAutomationscovering the UI, this works. Otherwise, consider awaiting a promise-returning version of the mutation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tsx` around lines 496 - 503, The persistAutomations function currently fire-and-forgets the react-query mutation saveAutomations, so callers may continue before automations finish saving; change persistAutomations to return or await the mutation promise (use saveAutomations.mutateAsync(...) or return the mutate call's promise) and update callers to await persistAutomations where needed so isSavingAutomations accurately reflects the in-flight operation and navigation/exit waits for completion.frontend/pages/policies/edit/components/SaveNewPolicyModal/SaveNewPolicyModal.tsx (1)
237-287: 💤 Low value
saveAutomationsswallows errors fromPromise.allwithout user feedback.If any of the automation API calls fail (lines 243-248, 265-270, 273-280),
Promise.allwill reject. This rejection propagates to the caller (onCreatePolicyinQueryEditor), which catches it and shows "Policy was created, but its automations couldn't be saved." — so error handling does exist upstream.However, the partial failure scenario isn't well-handled: if the team policy update succeeds but webhook update fails (or vice versa), the user won't know which part failed. Consider whether more granular feedback is needed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/pages/policies/edit/components/SaveNewPolicyModal/SaveNewPolicyModal.tsx` around lines 237 - 287, saveAutomations currently calls multiple API updates and uses Promise.all which rejects on the first failure and loses per-request status; change saveAutomations (the async function assigned when automations?.isDirty is true) to run each potential request individually or use Promise.allSettled for the array of requests created from automations.policyUpdate, automations.webhookOrTicketUpdate (teamPoliciesAPI.update, configAPI.update, teamsAPI.update), then inspect settled results and: 1) only apply queryClient.setQueryData / setConfig / updatedTeam for promises that fulfilled, 2) collect failures into a structured error/result that indicates which operation(s) failed (e.g., "policyUpdate" vs "webhookUpdate") and include their error messages, and 3) either throw that aggregated error or return the detailed result so onCreatePolicy can present granular feedback to the user.frontend/pages/policies/components/PolicyAutomationsFields/hooks/useScripts.ts (1)
9-28: 💤 Low valueHard
per_page: 1000cap silently truncates the picker list.If a fleet has more than 1000 scripts, options beyond the first page won't appear in the dropdown. Same pattern in
useSoftwareTitles. Likely acceptable for now, but worth confirming the cap exceeds realistic per-fleet counts.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/pages/policies/components/PolicyAutomationsFields/hooks/useScripts.ts` around lines 9 - 28, The hard-coded SCRIPTS_PAGE_SIZE = 1000 in useScripts causes silent truncation of dropdown options by limiting per_page to 1000; update useScripts (and the similar useSoftwareTitles) to avoid a fixed small cap by either supporting full pagination (fetch additional pages until exhausted) or accepting a configurable page size parameter/constant with a much higher default; change the call site in useQuery where per_page is set (the query key object passed into scriptsAPI.getScripts) to implement the chosen approach and ensure enabled/staleTime behavior remains unchanged.frontend/pages/policies/hooks/useUpdatePolicyAutomations.ts (1)
52-54: 💤 Low valueThrowing during the hook body crashes the render.
This guard executes on every render and throws synchronously in the React render path, taking down the component tree (no error boundary context here). Since this is a programmer-error invariant, prefer asserting/short-circuiting at the call site, or guard the mutation function instead so an invalid
teamIdForApirejects the mutation rather than crashing render.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/pages/policies/hooks/useUpdatePolicyAutomations.ts` around lines 52 - 54, The synchronous throw inside the hook body (checking isGlobalPolicy and teamIdForApi) crashes React renders; remove that throw and instead validate teamIdForApi when performing the mutation so invalid inputs reject the mutation rather than crashing render. Modify the mutation handler / mutate function in useUpdatePolicyAutomations (or the function passed to useMutation) to check if !isGlobalPolicy && teamIdForApi === undefined and then return a rejected Promise or throw inside the mutation callback (so it surfaces as a failed mutation), or alternatively short-circuit at call sites by asserting/returning early before calling the hook; update references to isGlobalPolicy and teamIdForApi accordingly. Ensure no synchronous throw remains in the hook body so renders cannot be interrupted.frontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx (1)
181-181: ⚡ Quick winRemove redundant boolean coercion.
initialIsWebhookEnabledis already a boolean (derived from boolean expressions on lines 91-93), so the!!operator is unnecessary.♻️ Proposed simplification
- if (isWebhookEnabled !== !!initialIsWebhookEnabled) return true; + if (isWebhookEnabled !== initialIsWebhookEnabled) return true;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx` at line 181, The comparison uses redundant boolean coercion: remove the unnecessary "!!" and compare isWebhookEnabled directly to initialIsWebhookEnabled in the OtherWorkflowsModal component (replace `if (isWebhookEnabled !== !!initialIsWebhookEnabled)` with `if (isWebhookEnabled !== initialIsWebhookEnabled)`), ensuring no change to types or behavior of the isWebhookEnabled and initialIsWebhookEnabled variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/pages/policies/details/PolicyDetailsPage/PolicyDetailsPage.tsx`:
- Around line 187-194: The team lookup is being disabled for
storedPolicy.team_id === 0 causing getTicketOrWebhookInfo to receive undefined
and return disabled automations; update the query `enabled` condition that gates
teamsAPI.load (where currently `enabled: !!policyTeamId && policyTeamId > 0`) to
allow 0 as a valid team id (e.g., `enabled: policyTeamId != null && policyTeamId
>= 0` or similar), so teamsAPI.load(0) runs and getTicketOrWebhookInfo receives
the proper team object (symbols: storedPolicy.team_id, policyTeamId,
teamsAPI.load, getTicketOrWebhookInfo).
In `@frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tsx`:
- Around line 306-320: The hook call uses an unsafe cast (policy: storedPolicy
as IPolicy) — change this so useUpdatePolicyAutomations is not invoked with a
potentially undefined policy: either move the useUpdatePolicyAutomations call
inside the conditional that guarantees storedPolicy exists (e.g., only call it
when storedPolicy !== undefined or when edit mode is true) or stop casting and
pass storedPolicy as-is and update useUpdatePolicyAutomations to accept policy?:
IPolicy and guard all internal accesses; reference the PolicyForm usage of
useUpdatePolicyAutomations, the storedPolicy variable, and the IPolicy type when
making the change.
In `@frontend/pages/policies/hooks/useUpdatePolicyAutomations.ts`:
- Around line 82-101: The concurrent Promise.all write can leave cache and
backend inconsistent if one call fails; update the mutation in
useUpdatePolicyAutomations.ts so the onError handler reconciles cache by
invalidating/refetching the affected queries (e.g., invalidateQueries('config'),
invalidateQueries('teams') and the specific policy query) or by using
queryClient.refetchQueries, and/or change the implementation to perform the
writes sequentially (call teamPoliciesAPI.update(...) first, then call
saveWebhookOrTicketMembership(...)) so partial success cannot leave stale
optimistic cache; reference the mutation wrapper in useMutation, the
policyUpdate and webhookOrTicketUpdate branches, and the
saveWebhookOrTicketMembership helper when adding invalidation/refetch logic in
onError or switching to sequential execution.
---
Outside diff comments:
In `@frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tests.tsx`:
- Around line 464-472: The test uses a nested waitFor and does not await
user.hover, causing flakiness; replace the inner waitFor by awaiting
user.hover(...) directly (await user.hover(screen.getByRole("button", { name:
"Run policy" }))) and then await a single waitFor that asserts the notice is
present (await waitFor(() => expect(screen.getByText(/live reports are
disabled/i)).toBeInTheDocument())); update the PolicyForm.tests.tsx test to
remove the nested waitFor and ensure both the hover and the assertion are
awaited.
---
Nitpick comments:
In
`@frontend/pages/policies/components/PolicyAutomationsFields/hooks/useScripts.ts`:
- Around line 9-28: The hard-coded SCRIPTS_PAGE_SIZE = 1000 in useScripts causes
silent truncation of dropdown options by limiting per_page to 1000; update
useScripts (and the similar useSoftwareTitles) to avoid a fixed small cap by
either supporting full pagination (fetch additional pages until exhausted) or
accepting a configurable page size parameter/constant with a much higher
default; change the call site in useQuery where per_page is set (the query key
object passed into scriptsAPI.getScripts) to implement the chosen approach and
ensure enabled/staleTime behavior remains unchanged.
In `@frontend/pages/policies/edit/components/PolicyForm/PolicyForm.tsx`:
- Around line 496-503: The persistAutomations function currently
fire-and-forgets the react-query mutation saveAutomations, so callers may
continue before automations finish saving; change persistAutomations to return
or await the mutation promise (use saveAutomations.mutateAsync(...) or return
the mutate call's promise) and update callers to await persistAutomations where
needed so isSavingAutomations accurately reflects the in-flight operation and
navigation/exit waits for completion.
In
`@frontend/pages/policies/edit/components/SaveNewPolicyModal/SaveNewPolicyModal.tsx`:
- Around line 237-287: saveAutomations currently calls multiple API updates and
uses Promise.all which rejects on the first failure and loses per-request
status; change saveAutomations (the async function assigned when
automations?.isDirty is true) to run each potential request individually or use
Promise.allSettled for the array of requests created from
automations.policyUpdate, automations.webhookOrTicketUpdate
(teamPoliciesAPI.update, configAPI.update, teamsAPI.update), then inspect
settled results and: 1) only apply queryClient.setQueryData / setConfig /
updatedTeam for promises that fulfilled, 2) collect failures into a structured
error/result that indicates which operation(s) failed (e.g., "policyUpdate" vs
"webhookUpdate") and include their error messages, and 3) either throw that
aggregated error or return the detailed result so onCreatePolicy can present
granular feedback to the user.
In `@frontend/pages/policies/hooks/useUpdatePolicyAutomations.ts`:
- Around line 52-54: The synchronous throw inside the hook body (checking
isGlobalPolicy and teamIdForApi) crashes React renders; remove that throw and
instead validate teamIdForApi when performing the mutation so invalid inputs
reject the mutation rather than crashing render. Modify the mutation handler /
mutate function in useUpdatePolicyAutomations (or the function passed to
useMutation) to check if !isGlobalPolicy && teamIdForApi === undefined and then
return a rejected Promise or throw inside the mutation callback (so it surfaces
as a failed mutation), or alternatively short-circuit at call sites by
asserting/returning early before calling the hook; update references to
isGlobalPolicy and teamIdForApi accordingly. Ensure no synchronous throw remains
in the hook body so renders cannot be interrupted.
In
`@frontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx`:
- Line 181: The comparison uses redundant boolean coercion: remove the
unnecessary "!!" and compare isWebhookEnabled directly to
initialIsWebhookEnabled in the OtherWorkflowsModal component (replace `if
(isWebhookEnabled !== !!initialIsWebhookEnabled)` with `if (isWebhookEnabled !==
initialIsWebhookEnabled)`), ensuring no change to types or behavior of the
isWebhookEnabled and initialIsWebhookEnabled variables.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4dee167e-b1d7-44e2-9a9d-42abf255d95b
⛔ Files ignored due to path filters (1)
assets/images/calendar-graphic.pngis excluded by!**/*.png
📒 Files selected for processing (76)
changes/42651-policy-automations-continuous-retryfrontend/components/CustomLink/_styles.scssfrontend/components/TableContainer/DataTable/_styles.scssfrontend/interfaces/policy.tsfrontend/pages/policies/ManagePoliciesPage/ManagePoliciesPage.tsxfrontend/pages/policies/ManagePoliciesPage/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/AutomationsModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventPreviewModal/CalendarEventPreviewModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventPreviewModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventPreviewModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventsModal/CalendarEventsModal.tests.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventsModal/CalendarEventsModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventsModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/CalendarEventsModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/ConditionalAccessModal/ConditionalAccessModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/ConditionalAccessModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/ExamplePayload/ExamplePayload.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/ExamplePayload/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/ExamplePayload/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/ExampleTicket/ExampleTicket.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/ExampleTicket/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/ExampleTicket/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/OtherWorkflowsModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/OtherWorkflowsModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/components/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/AutomationsModal/types.tsfrontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/CalendarEventsModal.tests.tsxfrontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/CalendarEventsModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/ConditionalAccessModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/ManageAutomationsModal/ManageAutomationsModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/ManageAutomationsModal/_styles.scssfrontend/pages/policies/ManagePoliciesPage/components/ManageAutomationsModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsxfrontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/index.tsfrontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/PoliciesTable.tests.tsxfrontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/PoliciesTable.tsxfrontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/PoliciesTableConfig.tsxfrontend/pages/policies/ManagePoliciesPage/components/PoliciesTable/_styles.scssfrontend/pages/policies/ManagePoliciesPage/helpers.tests.tsxfrontend/pages/policies/ManagePoliciesPage/helpers.tsxfrontend/pages/policies/components/PatchAutomationCta/PatchAutomationCta.tests.tsxfrontend/pages/policies/components/PatchAutomationCta/PatchAutomationCta.tsxfrontend/pages/policies/components/PatchAutomationCta/_styles.scssfrontend/pages/policies/components/PatchAutomationCta/index.tsfrontend/pages/policies/components/PolicyAutomationsFields/PolicyAutomationsFields.tsxfrontend/pages/policies/components/PolicyAutomationsFields/_styles.scssfrontend/pages/policies/components/PolicyAutomationsFields/hooks/index.tsfrontend/pages/policies/components/PolicyAutomationsFields/hooks/useScripts.tsfrontend/pages/policies/components/PolicyAutomationsFields/hooks/useSoftwareTitles.tsfrontend/pages/policies/components/PolicyAutomationsFields/index.tsfrontend/pages/policies/components/PolicyAutomationsFields/types.tsfrontend/pages/policies/components/PolicyAutomationsList/PolicyAutomationsList.tests.tsxfrontend/pages/policies/components/PolicyAutomationsList/PolicyAutomationsList.tsxfrontend/pages/policies/components/PolicyAutomationsList/_styles.scssfrontend/pages/policies/components/PolicyAutomationsList/index.tsfrontend/pages/policies/components/index.tsfrontend/pages/policies/details/PolicyDetailsPage/PolicyDetailsPage.tsxfrontend/pages/policies/edit/EditPolicyPage.tsxfrontend/pages/policies/edit/components/PolicyAutomations/PolicyAutomations.tsxfrontend/pages/policies/edit/components/PolicyAutomations/index.tsfrontend/pages/policies/edit/components/PolicyForm/PolicyForm.tests.tsxfrontend/pages/policies/edit/components/PolicyForm/PolicyForm.tsxfrontend/pages/policies/edit/components/SaveNewPolicyModal/SaveNewPolicyModal.tests.tsxfrontend/pages/policies/edit/components/SaveNewPolicyModal/SaveNewPolicyModal.tsxfrontend/pages/policies/edit/screens/QueryEditor.tsxfrontend/pages/policies/helpers.tsfrontend/pages/policies/hooks/index.tsfrontend/pages/policies/hooks/useUpdatePolicyAutomations.tsfrontend/services/entities/team_policies.ts
💤 Files with no reviewable changes (12)
- frontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/ConditionalAccessModal.tsx
- frontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/CalendarEventsModal.tests.tsx
- frontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/index.ts
- frontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/CalendarEventsModal.tsx
- frontend/pages/policies/edit/components/PolicyAutomations/index.ts
- frontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/_styles.scss
- frontend/pages/policies/ManagePoliciesPage/components/CalendarEventsModal/index.ts
- frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/index.ts
- frontend/pages/policies/ManagePoliciesPage/components/ConditionalAccessModal/_styles.scss
- frontend/pages/policies/ManagePoliciesPage/components/OtherWorkflowsModal/OtherWorkflowsModal.tsx
- frontend/pages/policies/edit/EditPolicyPage.tsx
- frontend/pages/policies/edit/components/PolicyAutomations/PolicyAutomations.tsx
Related issue: Resolves #42651
Checklist for submitter
changes/,orbit/changes/oree/fleetd-chrome/changes.See Changes files for more information.
Testing
New Fleet configuration settings
Summary by CodeRabbit
New Features
Improvements