Skip to content

Hide empty self-service categories on My device page (#48614)#48619

Open
marko-lisica wants to merge 1 commit into
mainfrom
marko/48614-hide-empty-self-service-categories
Open

Hide empty self-service categories on My device page (#48614)#48619
marko-lisica wants to merge 1 commit into
mainfrom
marko/48614-hide-empty-self-service-categories

Conversation

@marko-lisica

@marko-lisica marko-lisica commented Jul 2, 2026

Copy link
Copy Markdown
Member

Description

Resolves #48614.

On the My device page's Self-service tab, the category filter listed every category defined for the host's fleet — including categories that had no self-service software available for that host. Selecting such a category showed an empty list, which is confusing.

This change hides categories that have no self-service software items for the host, so users only see categories they can actually install from.

Implementation

The fix is client-side. The device self-service software endpoint is not paginated (per_page: 9999), so the frontend already holds the host's complete self-service software list, with each item's categories. That list has already been resolved by the backend software query for MDM enrollment, label scoping, and platform — so filtering the category dropdown against it is both correct and self-consistent with the existing per-category filtering.

  • Added filterCategoriesWithSoftware in SelfService/helpers.ts, which keeps only categories whose (case-insensitive) name matches a category present on some software item. It resolves category membership the same way filterSoftwareByCustomCategory already does (across software_package and app_store_app categories).
  • SelfServiceCard now derives visibleCategories and uses it everywhere downstream (the filter dropdown, the selected-category software list, and the stale-link recovery effect), so an empty category behaves as if it doesn't exist.
  • The stale-link recovery effect now also waits for the software list to load before acting, so a valid category_id isn't cleared during the load window.

Related issue: Resolves #48614

Checklist for submitter

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
  • 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.
  • If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes

Testing

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

Note: this is a frontend-only change; no backend endpoints, database schema, or configuration settings were modified.

Summary by CodeRabbit

  • New Features

    • On the My device page, self-service category filters now hide categories that don’t have any available software.
    • Categories are matched more flexibly, including case-insensitive names and app store app categories.
  • Bug Fixes

    • Prevented empty or unavailable categories from appearing in the dropdown.
    • Improved category selection behavior so valid categories stay visible and aren’t cleared prematurely.

@marko-lisica marko-lisica requested a review from a team as a code owner July 2, 2026 13:38

@claude claude Bot left a comment

Copy link
Copy Markdown

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.

@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.01%. Comparing base (73b0485) to head (e1af987).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main   #48619    +/-   ##
========================================
  Coverage   68.01%   68.01%            
========================================
  Files        3678     3678            
  Lines      233764   233780    +16     
  Branches    12268    12419   +151     
========================================
+ Hits       158999   159015    +16     
  Misses      60470    60470            
  Partials    14295    14295            
Flag Coverage Δ
frontend 58.98% <100.00%> (+0.01%) ⬆️

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

☔ View full report in Codecov by Harness.
📢 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.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This change hides self-service software categories that have no available software from the category filter dropdown on the My device page. A new helper, filterCategoriesWithSoftware, filters categories based on matching software items (from software_package or app_store_app categories, case-insensitively). SelfServiceCard derives a visibleCategories list using this helper, applies it to category-based software filtering, updates stale-link recovery logic to validate against visible categories only after data loads, and passes visibleCategories to both mobile and desktop filter components. Tests were added/updated for the helper and component, along with a changelog entry.

Changes

Area Change
Helper Added filterCategoriesWithSoftware to filter categories with no matching software
Component SelfServiceCard computes and uses visibleCategories; stale-link effect updated to wait for data and validate against visible categories
UI wiring Mobile and desktop SelfServiceFilters receive visibleCategories instead of categories
Tests New/updated tests for helper filtering and category hiding behavior
Changelog Added entry documenting the behavior

Sequence Diagram(s)

sequenceDiagram
  participant SelfServiceCard
  participant filterCategoriesWithSoftware
  participant SelfServiceFilters
  SelfServiceCard->>filterCategoriesWithSoftware: categories, enhancedSoftware
  filterCategoriesWithSoftware-->>SelfServiceCard: visibleCategories
  SelfServiceCard->>SelfServiceCard: filter softwareInSelectedCategory
  SelfServiceCard->>SelfServiceCard: validate category_id vs visibleCategories
  SelfServiceCard->>SelfServiceFilters: render with visibleCategories
Loading

Related Issues

Suggested Labels: frontend, self-service, bug

Suggested Reviewers: none identified from provided context

Poem
A rabbit peeked behind each tab,
Found empty shelves — no software, drab.
So off they went, tucked out of sight,
Now only stocked shelves show the light.
Hop, filter, hide — the list feels right! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main user-facing change and matches the implemented category-hiding behavior.
Description check ✅ Passed The description follows the template well, includes the related issue, implementation, and testing sections, and is mostly complete.
Linked Issues check ✅ Passed The PR hides empty self-service categories as requested in #48614 by filtering categories to ones with matching software.
Out of Scope Changes check ✅ Passed The changes stay focused on the self-service category filter and related tests, with no obvious unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 marko/48614-hide-empty-self-service-categories

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.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (2)
frontend/pages/hosts/details/cards/Software/SelfService/helpers.ts (1)

103-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Correct implementation; consider deduplicating category extraction.

The new helper correctly reuses the same case-insensitive matching semantics as filterSoftwareByCustomCategory (lines 93-99 in this file). Both functions independently build [...software_package?.categories ?? [], ...app_store_app?.categories ?? []] — extracting this into a small shared helper (e.g., getItemCategoryNames(item)) would keep the two matching rules from silently diverging if either is updated later.

♻️ Proposed refactor
+const getItemCategoryNames = (item: IDeviceSoftwareWithUiStatus): string[] => [
+  ...(item.software_package?.categories ?? []),
+  ...(item.app_store_app?.categories ?? []),
+];
+
 export const filterSoftwareByCustomCategory = (
   software: IDeviceSoftwareWithUiStatus[],
   categories: ISelfServiceCategory[],
   categoryId?: number
 ): IDeviceSoftwareWithUiStatus[] => {
   ...
-  return software.filter((item) => {
-    const itemCategories = [
-      ...(item.software_package?.categories ?? []),
-      ...(item.app_store_app?.categories ?? []),
-    ];
-    return itemCategories.some((c) => c.toLowerCase() === normalized);
-  });
+  return software.filter((item) =>
+    getItemCategoryNames(item).some((c) => c.toLowerCase() === normalized)
+  );
 };

 export const filterCategoriesWithSoftware = (
   categories: ISelfServiceCategory[],
   software: IDeviceSoftwareWithUiStatus[]
 ): ISelfServiceCategory[] => {
   const categoryNamesInUse = new Set<string>();
-  software.forEach((item) => {
-    [
-      ...(item.software_package?.categories ?? []),
-      ...(item.app_store_app?.categories ?? []),
-    ].forEach((name) => categoryNamesInUse.add(name.toLowerCase()));
-  });
+  software.forEach((item) =>
+    getItemCategoryNames(item).forEach((name) =>
+      categoryNamesInUse.add(name.toLowerCase())
+    )
+  );
   return categories.filter((c) => categoryNamesInUse.has(c.name.toLowerCase()));
 };
🤖 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/Software/SelfService/helpers.ts` around
lines 103 - 125, The category matching logic is duplicated between
filterCategoriesWithSoftware and filterSoftwareByCustomCategory, which risks the
two paths diverging later. Extract the shared category-name collection into a
small helper (for example, a getItemCategoryNames-style function) and reuse it
in both places so the lowercased matching behavior stays identical for
software_package and app_store_app categories.
frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceCard/SelfServiceCard.tests.tsx (1)

196-218: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a regression test for the loading-window fix.

The PR's stated goal is to stop clearing a valid category_id while selfServiceData is still loading (categories resolved, software not yet). Existing tests only cover the "should clear" paths (empty/unknown categories); none assert that a valid category_id survives while selfServiceData is undefined and isCategoriesSuccess is true. Given this behavior was explicitly called out as the bug being fixed, a direct test would guard against regressions.

🤖 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/Software/SelfService/SelfServiceCard/SelfServiceCard.tests.tsx`
around lines 196 - 218, Add a regression test in SelfServiceCard.tests.tsx
covering the loading-window case where categories have loaded successfully but
selfServiceData is still undefined and a valid category_id is present. Use
SelfServiceCard with createTestProps, createMockRouter, and the existing
listDeviceSelfServiceCategoriesHandler setup, then assert that the router push
logic does not remove category_id while loading and only preserves the valid
filter state. This should complement the existing auto-clear test and
specifically verify the behavior around SelfServiceCard's category handling when
isCategoriesSuccess is true but data is still pending.
🤖 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.

Nitpick comments:
In `@frontend/pages/hosts/details/cards/Software/SelfService/helpers.ts`:
- Around line 103-125: The category matching logic is duplicated between
filterCategoriesWithSoftware and filterSoftwareByCustomCategory, which risks the
two paths diverging later. Extract the shared category-name collection into a
small helper (for example, a getItemCategoryNames-style function) and reuse it
in both places so the lowercased matching behavior stays identical for
software_package and app_store_app categories.

In
`@frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceCard/SelfServiceCard.tests.tsx`:
- Around line 196-218: Add a regression test in SelfServiceCard.tests.tsx
covering the loading-window case where categories have loaded successfully but
selfServiceData is still undefined and a valid category_id is present. Use
SelfServiceCard with createTestProps, createMockRouter, and the existing
listDeviceSelfServiceCategoriesHandler setup, then assert that the router push
logic does not remove category_id while loading and only preserves the valid
filter state. This should complement the existing auto-clear test and
specifically verify the behavior around SelfServiceCard's category handling when
isCategoriesSuccess is true but data is still pending.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 02983817-d78c-46a5-98aa-3d8c46b8216b

📥 Commits

Reviewing files that changed from the base of the PR and between 7023c5b and e1af987.

📒 Files selected for processing (5)
  • changes/48614-hide-empty-self-service-categories
  • frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceCard/SelfServiceCard.tests.tsx
  • frontend/pages/hosts/details/cards/Software/SelfService/SelfServiceCard/SelfServiceCard.tsx
  • frontend/pages/hosts/details/cards/Software/SelfService/helpers.tests.ts
  • frontend/pages/hosts/details/cards/Software/SelfService/helpers.ts

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.

Self-service: hide empty categories

1 participant