Skip to content

Fleet UI: Host details page empty states#44884

Merged
RachelElysia merged 9 commits intomainfrom
35483-empty-states-host-details-page
May 8, 2026
Merged

Fleet UI: Host details page empty states#44884
RachelElysia merged 9 commits intomainfrom
35483-empty-states-host-details-page

Conversation

@RachelElysia
Copy link
Copy Markdown
Member

@RachelElysia RachelElysia commented May 6, 2026

Issue

Closes #35483

Description

Screenrecording

Shows host details page > software library, reports, and policies empty states

Screen.Recording.2026-05-07.at.12.27.35.PM.mov

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

Release Notes

  • New Features

    • Added schedule report functionality with permission-based controls
    • Added manage policies CTA with conditional button visibility
    • Added software installation capability with role-based permissions
    • Policies tab now conditionally displays based on device type
  • Improvements

    • Enhanced empty states with contextual action buttons
    • Improved search and filter control behavior in tables
    • Better permission-derived feature visibility across host details pages

@RachelElysia
Copy link
Copy Markdown
Member Author

@claude review

@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 60.93750% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.80%. Comparing base (c79d33a) to head (a929227).
⚠️ Report is 44 commits behind head on main.

Files with missing lines Patch % Lines
.../hosts/details/HostDetailsPage/HostDetailsPage.tsx 0.00% 17 Missing ⚠️
.../cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx 0.00% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #44884      +/-   ##
==========================================
+ Coverage   66.73%   66.80%   +0.07%     
==========================================
  Files        2675     2693      +18     
  Lines      215826   216454     +628     
  Branches     9946    10184     +238     
==========================================
+ Hits       144025   144609     +584     
- Misses      58703    58746      +43     
- Partials    13098    13099       +1     
Flag Coverage Δ
frontend 55.24% <60.93%> (+0.86%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread frontend/pages/hosts/details/cards/Policies/HostPolicies.tsx
Comment thread frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx Outdated
Comment thread frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tsx
Comment thread frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tsx Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Review Change Stack

Walkthrough

This pull request normalizes empty state handling across host-detail UI components. It adds a disableSearch prop to TableContainer to disable search fields in truly empty states, and introduces consistent empty state patterns across four host-detail tables/cards: HostReportsTab, HostSoftwareLibraryTable, HostPolicies, and HostSoftwareTable. Permission-based call-to-action buttons are conditionally rendered (schedule report, add software, manage policies) when users have required permissions. The empty state logic distinguishes between truly empty (no data, no search, no filters) versus filtered-empty (results present but filtered/searched). Supporting styling adds disabled states to input fields and filter controls, and introduces TableCount styling for consistent result counts.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: implementing updated empty states for the host details page.
Description check ✅ Passed The description provides the issue number, scope (part 3 of #35483), a screen recording, and confirms testing was performed. However, it does not follow the provided template structure with checklists.
Linked Issues check ✅ Passed The PR directly addresses the goal from #35483 by implementing normalized empty states for the host details page (software library, reports, and policies), matching the Figma design specifications provided.
Out of Scope Changes check ✅ Passed All changes are focused on implementing empty states and related UI updates for the host details page subcomponents. No unrelated modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 35483-empty-states-host-details-page

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@RachelElysia
Copy link
Copy Markdown
Member Author

@claude review

Comment thread frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
Comment thread frontend/pages/hosts/details/cards/Policies/HostPolicies.tsx Outdated
@RachelElysia RachelElysia marked this pull request as ready for review May 7, 2026 18:14
@RachelElysia RachelElysia requested a review from a team as a code owner May 7, 2026 18:14
Copilot AI review requested due to automatic review settings May 7, 2026 18:14
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibraryTable/HostSoftwareLibraryTable.tsx`:
- Around line 46-47: The Add software CTA can be enabled via canAddSoftware but
leave onAddSoftware undefined, causing a clickable button with no action; update
the HostSoftwareLibraryTable component to require both conditions before
enabling the button and binding the handler (i.e., only render an enabled Add
button or attach the onClick when canAddSoftware && typeof onAddSoftware ===
'function'), and similarly apply the same guard for the other Add button/render
block around the code referenced by the 167-173 area so the UI is disabled or
non-interactive if onAddSoftware is not provided.

In `@frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tsx`:
- Around line 76-77: The Schedule CTA currently renders whenever
canScheduleReport is true even if onScheduleReport is absent, producing a no-op
button; update the HostReportsTab render logic to only render (or enable) the
"Schedule a report" button when both canScheduleReport and a callable
onScheduleReport exist (e.g. canScheduleReport && typeof onScheduleReport ===
'function'), and apply the same guard where the CTA is rendered at lines
~261-267 so the button is never clickable without a handler (alternatively make
onScheduleReport required in the props if appropriate).
🪄 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: a155fb5d-239d-4a31-ad1d-7b02bf201003

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1206d and a929227.

📒 Files selected for processing (15)
  • frontend/components/TableContainer/TableContainer.tsx
  • frontend/components/TableContainer/TableCount/TableCount.tsx
  • frontend/components/TableContainer/TableCount/_styles.scss
  • frontend/components/forms/fields/InputFieldWithIcon/_styles.scss
  • frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/_styles.scss
  • frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
  • frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tests.tsx
  • frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tsx
  • frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx
  • frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibraryTable/HostSoftwareLibraryTable.tests.tsx
  • frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibraryTable/HostSoftwareLibraryTable.tsx
  • frontend/pages/hosts/details/cards/Policies/HostPolicies.tests.tsx
  • frontend/pages/hosts/details/cards/Policies/HostPolicies.tsx
  • frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tests.tsx
  • frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx

Comment on lines +46 to +47
canAddSoftware?: boolean;
onAddSoftware?: () => void;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard “Add software” CTA against missing click handler

canAddSoftware and onAddSoftware are independently optional, so this can render an enabled button with no action when canAddSoftware === true but onAddSoftware is unset.

💡 Suggested fix
-          primaryButton={
-            canAddSoftware ? (
+          primaryButton={
+            canAddSoftware && onAddSoftware ? (
               <Button onClick={onAddSoftware} type="button">
                 Add software
               </Button>
             ) : undefined
           }

Also applies to: 167-173

🤖 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/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibraryTable/HostSoftwareLibraryTable.tsx`
around lines 46 - 47, The Add software CTA can be enabled via canAddSoftware but
leave onAddSoftware undefined, causing a clickable button with no action; update
the HostSoftwareLibraryTable component to require both conditions before
enabling the button and binding the handler (i.e., only render an enabled Add
button or attach the onClick when canAddSoftware && typeof onAddSoftware ===
'function'), and similarly apply the same guard for the other Add button/render
block around the code referenced by the 167-173 area so the UI is disabled or
non-interactive if onAddSoftware is not provided.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave them optional. It's the right design — you only need onAddSoftware when canAddSoftware is true, and the only caller follows that
contract. Not a bug.

Comment on lines +76 to +77
canScheduleReport?: boolean;
onScheduleReport?: () => void;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent rendering a no-op “Schedule a report” button

The CTA is gated only by canScheduleReport, but onScheduleReport is optional. This can expose a clickable button that does nothing.

💡 Suggested fix
-          primaryButton={
-            canScheduleReport ? (
+          primaryButton={
+            canScheduleReport && onScheduleReport ? (
               <Button onClick={onScheduleReport} type="button">
                 Schedule a report
               </Button>
             ) : undefined
           }

Also applies to: 261-267

🤖 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/hosts/details/HostReportsTab/HostReportsTab.tsx` around lines
76 - 77, The Schedule CTA currently renders whenever canScheduleReport is true
even if onScheduleReport is absent, producing a no-op button; update the
HostReportsTab render logic to only render (or enable) the "Schedule a report"
button when both canScheduleReport and a callable onScheduleReport exist (e.g.
canScheduleReport && typeof onScheduleReport === 'function'), and apply the same
guard where the CTA is rendered at lines ~261-267 so the button is never
clickable without a handler (alternatively make onScheduleReport required in the
props if appropriate).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same situation — one caller, always passes both. The test (line 110) passes canScheduleReport: false without onScheduleReport, which is why it's optional. Not a bug.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Host details page tab empty states (Reports, Software inventory/library, and Policies) to align with the “Normalize empty states in Fleet UI” effort, including disabling irrelevant controls in “truly empty” scenarios and adding permission-based CTAs.

Changes:

  • Add “truly empty” empty-state UIs for Host Reports, Host Software tables, Host Software Library, and Host Policies, with disabled search/filter/sort controls.
  • Add permission-aware CTAs (e.g., “Schedule a report”, “Add software”, “Manage policies”) and wire permissions from HostDetailsPage.
  • Extend TableContainer to support disabling its search input and introduce a styled TableCount component for consistent counts.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/pages/hosts/ManageHostsPage/components/LabelFilterSelect/_styles.scss Adds disabled styling for the label filter select control.
frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tsx Introduces a new “No reports scheduled” empty state, disables controls when truly empty, and adds optional scheduling CTA.
frontend/pages/hosts/details/HostReportsTab/HostReportsTab.tests.tsx Adds test coverage for new reports empty states and control disabling.
frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx Adds per-host-team permission checks and wires CTAs into Reports/Policies tabs; hides Policies tab on unsupported platforms.
frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx Adds “No software found” truly-empty state; disables search/filter controls when truly empty.
frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tests.tsx Updates/adds tests for the new truly-empty vs filtered-empty behavior and disabled controls.
frontend/pages/hosts/details/cards/Policies/HostPolicies.tsx Adds truly-empty policies state with count + optional “Manage policies” CTA; switches to TableCount.
frontend/pages/hosts/details/cards/Policies/HostPolicies.tests.tsx Adds tests for new policies empty state copy/CTA behavior and count rendering.
frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibraryTable/HostSoftwareLibraryTable.tsx Adds truly-empty library state with optional “Add software” CTA; disables search/sort filter when truly empty.
frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibraryTable/HostSoftwareLibraryTable.tests.tsx Adds tests for new library empty states, CTA visibility, and disabled search.
frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx Adjusts “Add software” permission to be based on the host’s team (not nav-selected team) and passes CTA props down.
frontend/components/TableContainer/TableCount/TableCount.tsx Adds a class for consistent styling of table counts.
frontend/components/TableContainer/TableCount/_styles.scss Defines .table-count styles.
frontend/components/TableContainer/TableContainer.tsx Adds disableSearch prop to disable the SearchField input.
frontend/components/forms/fields/InputFieldWithIcon/_styles.scss Improves disabled-state icon coloring for inputs with icons.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +256 to +266
info={
canScheduleReport
? "Select Refetch to load the latest data from this host, or schedule a report."
: "Select Refetch to load the latest data from this host."
}
primaryButton={
canScheduleReport ? (
<Button onClick={onScheduleReport} type="button">
Schedule a report
</Button>
) : undefined
Comment on lines +160 to +172
<EmptyState
header="No software found"
info={
canAddSoftware
? "Add software to install on this host."
: "No software has been added for this host."
}
primaryButton={
canAddSoftware ? (
<Button onClick={onAddSoftware} type="button">
Add software
</Button>
) : undefined
Comment on lines +133 to +149
const target = deviceUser ? "your device" : "this host";
const manageClause = canManagePolicies
? ", or manage its policies."
: ".";

return (
<EmptyState
header={
<>
No policies are checked{" "}
{deviceUser ? `on your device` : `for this host`}
</>
}
info={
<>
Expecting to see policies? Try selecting “Refetch” to ask{" "}
{deviceUser ? `your device ` : `this host `}
to report new vitals.
</>
}
/>
<>
<TableCount name="policies" count={0} />
<EmptyState
header="No policies checked"
info={`Select Refetch to load the latest data from ${target}${manageClause}`}
primaryButton={
canManagePolicies ? (
<Button onClick={onManagePolicies} type="button">
Manage policies
</Button>
) : undefined
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, same thing. One caller (line 1604-1605), always passes both. Tests pass canManagePolicies: false without the handler. Not a bug. All three of these are the same pattern — the review flagged a theoretical type-level mismatch, but in practice the contract is always followed. These are all fine.

Comment on lines 156 to +170
return (
<>
{renderBanner()}
<TableContainer
columnConfigs={tableHeaders}
data={generatePolicyDataSet(policies, !!conditionalAccessEnabled)}
isLoading={isLoading}
defaultSortHeader="status"
resultsTitle="policies"
emptyComponent={() => <></>}
showMarkAllPages={false}
isAllPagesSelected={false}
disableCount
renderCount={() => (
<TableCount name="policies" count={policies.length} />
)}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring to use emptyComponent={() => <></>} and remove the extra renderCount, PR incoming

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix in #45039

@RachelElysia RachelElysia merged commit 258159e into main May 8, 2026
28 checks passed
@RachelElysia RachelElysia deleted the 35483-empty-states-host-details-page branch May 8, 2026 13:25
@RachelElysia
Copy link
Copy Markdown
Member Author

Followup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Normalize empty states in Fleet UI

3 participants