Skip to content

ENG-2851: [DEMO] Add LLM classification report and Classify with AI button#7528

Open
thabofletcher wants to merge 4 commits intomainfrom
ENG-2851-llm-export-report
Open

ENG-2851: [DEMO] Add LLM classification report and Classify with AI button#7528
thabofletcher wants to merge 4 commits intomainfrom
ENG-2851-llm-export-report

Conversation

@thabofletcher
Copy link
Contributor

@thabofletcher thabofletcher commented Feb 28, 2026

Ticket ENG-2851

⚠️ TEMPORARY DEMO CODE

This PR contains temporary code for sales demonstrations. It should not be considered production-ready and may be removed or significantly refactored before general release.

Description Of Changes

Adds demo UI for LLM classification of website monitor discovered assets. This includes a "Classify with AI" button and a classification report modal to showcase LLM classification capabilities.

Code Changes

  • Add alphaWebMonitorClassifierDemoUI feature flag for demo UI components
  • Add "Classify with AI" button to trigger LLM classification on discovered assets
  • Add ClassificationReportModal showing:
    • Coverage statistics (Compass vs LLM vs unclassified)
    • Category and confidence distributions
    • Vendor matching stats
    • Flagged resources and sample classifications
  • Add "Report" button to view classification statistics

Related PRs

Steps to Confirm

  1. Enable alphaWebMonitorClassifierDemoUI feature flag
  2. Navigate to discovered assets table for a website monitor
  3. Verify "Classify with AI" button appears
  4. Verify "Report" button appears
  5. Click Report to view classification statistics modal

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
    • Add a db-migration This indicates that a change includes a database migration label to the entry if your change includes a DB migration
    • Add a high-risk This issue suggests changes that have a high-probability of breaking existing code label to the entry if your change includes a high-risk change (i.e. potential for performance impact or unexpected regression) that should be flagged
    • Updates unreleased work already in Changelog, no new entry necessary
  • UX feedback:
    • All UX related changes have been reviewed by a designer
    • No UX review needed
  • Followup issues:
    • Followup issues created
    • No followup issues
  • Database migrations:
    • Ensure that your downrev is up to date with the latest revision on main
    • Ensure that your downgrade() migration is correct and works
      • If a downgrade migration is not possible for this change, please call this out in the PR description!
    • No migrations
  • Documentation:
    • Documentation complete, PR opened in fidesdocs
    • Documentation issue created in fidesdocs
    • If there are any new client scopes created as part of the pull request, remember to update public-facing documentation that references our scope registry
    • No documentation updates required

Summary by CodeRabbit

  • New Features
    • Added "Classify with AI" bulk action allowing automated classification of discovered website assets.
    • New classification report viewer displays detailed metrics including coverage analysis, category and confidence distribution, vendor matching results, resource-type breakdown, and collapsible lists of flagged resources and sample classifications.

- Add alphaWebMonitorClassifyWithAI feature flag (separate from config flag)
- Add ClassificationReportModal component for viewing LLM classification stats
- Add Classify with AI button to DiscoveredAssetsTable
- Add classifyWebsiteAssets mutation and getClassificationReport query
- Report shows coverage, category distribution, confidence scores, vendor matching

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@vercel
Copy link
Contributor

vercel bot commented Feb 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
fides-plus-nightly Ready Ready Preview, Comment Mar 4, 2026 3:56pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Mar 4, 2026 3:56pm

Request Review

@thabofletcher thabofletcher marked this pull request as ready for review February 28, 2026 22:09
@thabofletcher thabofletcher requested a review from a team as a code owner February 28, 2026 22:09
@thabofletcher thabofletcher requested review from jpople and removed request for a team February 28, 2026 22:09
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 28, 2026

Greptile Summary

This PR adds temporary demo UI for LLM classification of website monitor discovered assets. The implementation includes a "Classify with AI" button to trigger classification and a comprehensive classification report modal that displays coverage statistics, category/confidence distributions, vendor matching stats, and sample classifications.

Key Changes

  • Added ClassificationReportModal component with detailed classification statistics and sample data
  • Added two new RTK Query endpoints: classifyWebsiteAssets mutation and getClassificationReport query
  • Integrated "Classify with AI" functionality into the bulk actions menu and as a standalone button
  • Added "Report" button to view classification statistics
  • All features properly gated behind alphaWebMonitorClassifierDemoUI feature flag (development-only)

Code Quality

The implementation follows existing patterns in the codebase:

  • Proper TypeScript typing throughout
  • RTK Query endpoints include appropriate cache invalidation tags
  • Error handling with toast notifications
  • Feature flag properly configured for development environment only
  • Component structure and styling consistent with existing code

Since this is explicitly marked as temporary demo code, the implementation is appropriately focused on functionality over long-term maintainability.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk as it's demo code properly isolated behind a development-only feature flag
  • The code is well-structured, follows existing patterns, includes proper error handling, and is completely isolated behind a feature flag that's only enabled in development. No production impact or breaking changes.
  • No files require special attention

Important Files Changed

Filename Overview
clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx New modal component for displaying LLM classification statistics; well-structured with proper TypeScript types and Ant Design components
clients/admin-ui/src/features/data-discovery-and-detection/action-center/action-center.slice.ts Adds TypeScript interfaces for classification report and two new RTK Query endpoints with proper cache invalidation tags
clients/admin-ui/src/features/data-discovery-and-detection/action-center/hooks/useDiscoveredAssetsTable.tsx Adds handleClassifyWithAI callback function and integrates classification mutation with proper error handling and toast notifications
clients/admin-ui/src/features/data-discovery-and-detection/action-center/tables/DiscoveredAssetsTable.tsx Adds Classify with AI button and Report button to UI, properly gated behind alphaWebMonitorClassifierDemoUI feature flag
clients/admin-ui/src/flags.json Adds alphaWebMonitorClassifierDemoUI feature flag with appropriate development-only settings and clear description

Last reviewed commit: 6bb5357

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

5 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@speaker-ender speaker-ender requested review from speaker-ender and removed request for jpople March 2, 2026 13:09
Copy link
Contributor

@speaker-ender speaker-ender left a comment

Choose a reason for hiding this comment

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

Minor color alignments with theme

@speaker-ender speaker-ender force-pushed the ENG-2851-llm-export-report branch from c45fb22 to bea8e75 Compare March 4, 2026 15:51
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

This PR introduces AI-based classification functionality for website assets in the data discovery module. It adds a new modal component for viewing classification reports, creates API endpoints for triggering classification and retrieving reports, integrates the feature into the assets table with a new action button, and gates the functionality behind a feature flag.

Changes

Cohort / File(s) Summary
New Classification Modal Component
clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx
Adds a new React component that renders a detailed classification report inside a modal, displaying coverage metrics, category and confidence distributions, vendor matching, resource-type breakdowns, and flagged/sampled resources via collapsible tables. Fetches data via useGetClassificationReportQuery and handles loading and error states.
API Endpoints & Types
clients/admin-ui/src/features/data-discovery-and-detection/action-center/action-center.slice.ts
Introduces WebsiteClassificationReport type and supporting classification-related types; adds two new API endpoints: classifyWebsiteAssets (mutation to trigger classification) and getClassificationReport (query to fetch report data); exports corresponding React hooks.
Hook Integration
clients/admin-ui/src/features/data-discovery-and-detection/action-center/hooks/useDiscoveredAssetsTable.tsx
Imports and integrates useClassifyWebsiteAssetsMutation; adds handleClassifyWithAI action and isClassifyingAssets loading state to the hook's public API; includes the new mutation in bulk action loading aggregation.
UI Feature Integration
clients/admin-ui/src/features/data-discovery-and-detection/action-center/tables/DiscoveredAssetsTable.tsx
Adds feature-flag-controlled UI for AI classification: "Classify with AI" bulk action button and "Report" button; manages ClassificationReportModal state and passes necessary props; integrates loading state from hook.
Feature Flag Configuration
clients/admin-ui/src/flags.json
Adds new feature flag alphaWebMonitorClassifierDemoUI to control LLM classification UI availability (enabled in development only).

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as DiscoveredAssetsTable
    participant Hook as useDiscoveredAssetsTable
    participant Mutation as classifyWebsiteAssets<br/>(API)
    participant API as Backend
    participant Modal as ClassificationReportModal
    participant Query as getClassificationReport<br/>(API)

    User->>UI: Clicks "Classify with AI"
    UI->>Hook: handleClassifyWithAI(monitorId, selectedUrns)
    Hook->>Mutation: Invoke mutation with params
    Mutation->>API: POST /classify-assets
    API-->>Mutation: MonitorActionResponse
    Mutation-->>Hook: Success/Error
    Hook-->>UI: Toast notification
    UI->>User: Display success/error message

    User->>UI: Clicks "Report" button
    UI->>Modal: Opens ClassificationReportModal (open=true)
    Modal->>Query: useGetClassificationReportQuery(monitorId)
    Query->>API: GET /classification-report
    API-->>Query: WebsiteClassificationReport
    Query-->>Modal: Report data
    Modal->>Modal: Render report sections (coverage, distribution, resources, etc.)
    Modal-->>User: Display detailed classification report
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through data lands,
With AI's touch and careful hands,
Classification now takes flight,
Reports displayed, shining bright! 🐰✨
New features bloom where assets meet,
Making discovery complete!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: adding a demo UI with LLM classification report and a 'Classify with AI' button, accurately reflected in the changeset.
Description check ✅ Passed The description follows the template structure with all key sections completed: ticket reference, clear description of changes, code changes listed, confirmation steps, and pre-merge checklist mostly addressed with appropriate selections.
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 (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ENG-2851-llm-export-report

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

Copy link

@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

🧹 Nitpick comments (1)
clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx (1)

317-320: Use a nullish check for numeric confidence rendering.

Line 318 uses a truthy check; a valid 0 confidence would render as "-". Prefer explicit null/undefined checks.

♻️ Proposed fix
-                      render: (score: number) =>
-                        score ? (
+                      render: (score?: number) =>
+                        score !== null && score !== undefined ? (
                           <Tag color={getConfidenceColor(score)}>{score}</Tag>
                         ) : (
                           "-"
                         ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx`
around lines 317 - 320, The confidence cell renderer in
ClassificationReportModal.tsx uses a truthy check (render: (score: number) =>
score ? ...) which treats 0 as falsy and shows "-" incorrectly; change the
condition to an explicit nullish check (e.g., score != null or score !== null &&
score !== undefined) so that 0 is rendered inside <Tag
color={getConfidenceColor(score)}>{score}</Tag> while null/undefined still
render the fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx`:
- Around line 49-59: getCategoryColor currently calls category.toLowerCase()
without guarding for undefined/null which can crash when items have optional
category; update getCategoryColor to first coerce or guard the incoming category
(e.g., treat undefined/null as "unknown" or an empty string) before calling
toLowerCase, then look up the colors map (advertising, analytics, social_media,
functional, essential, unknown) and return the default tag when no match; ensure
the function signature and callers (getCategoryColor) handle optional string
input safely.

In
`@clients/admin-ui/src/features/data-discovery-and-detection/action-center/hooks/useDiscoveredAssetsTable.tsx`:
- Around line 627-631: The toast message in useDiscoveredAssetsTable.tsx
currently states "Classification complete..." but the mutation is
task-based/async; update the message passed to successToastParams (where toast
is called with selectedUrns and successToastParams) to reflect that the
operation was started/queued (e.g., "Classification started for {count}
uncategorized assets." or "Classification queued for {count} uncategorized
assets.") so it doesn't imply immediate completion.

---

Nitpick comments:
In
`@clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx`:
- Around line 317-320: The confidence cell renderer in
ClassificationReportModal.tsx uses a truthy check (render: (score: number) =>
score ? ...) which treats 0 as falsy and shows "-" incorrectly; change the
condition to an explicit nullish check (e.g., score != null or score !== null &&
score !== undefined) so that 0 is rendered inside <Tag
color={getConfidenceColor(score)}>{score}</Tag> while null/undefined still
render the fallback.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60b04f3a-ea48-47c1-885d-8bd3bd1cef55

📥 Commits

Reviewing files that changed from the base of the PR and between 789ec53 and bea8e75.

📒 Files selected for processing (5)
  • clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx
  • clients/admin-ui/src/features/data-discovery-and-detection/action-center/action-center.slice.ts
  • clients/admin-ui/src/features/data-discovery-and-detection/action-center/hooks/useDiscoveredAssetsTable.tsx
  • clients/admin-ui/src/features/data-discovery-and-detection/action-center/tables/DiscoveredAssetsTable.tsx
  • clients/admin-ui/src/flags.json

Comment on lines +49 to +59
const getCategoryColor = (category: string): TagColor => {
const colors: Record<string, TagColor> = {
advertising: "error",
analytics: "minos",
social_media: "nectar",
functional: "success",
essential: "info",
unknown: "default",
};
return colors[category.toLowerCase()] || "default";
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard category normalization to prevent runtime crashes.

getCategoryColor assumes category is always defined, but flagged/sample items can have optional category. Calling .toLowerCase() on undefined will throw at runtime (e.g., Line 245 usage path).

🐛 Proposed fix
-const getCategoryColor = (category: string): TagColor => {
+const getCategoryColor = (category?: string): TagColor => {
   const colors: Record<string, TagColor> = {
     advertising: "error",
     analytics: "minos",
     social_media: "nectar",
     functional: "success",
     essential: "info",
     unknown: "default",
   };
-  return colors[category.toLowerCase()] || "default";
+  if (!category) {
+    return "default";
+  }
+  return colors[category.toLowerCase()] || "default";
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getCategoryColor = (category: string): TagColor => {
const colors: Record<string, TagColor> = {
advertising: "error",
analytics: "minos",
social_media: "nectar",
functional: "success",
essential: "info",
unknown: "default",
};
return colors[category.toLowerCase()] || "default";
};
const getCategoryColor = (category?: string): TagColor => {
const colors: Record<string, TagColor> = {
advertising: "error",
analytics: "minos",
social_media: "nectar",
functional: "success",
essential: "info",
unknown: "default",
};
if (!category) {
return "default";
}
return colors[category.toLowerCase()] || "default";
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/admin-ui/src/features/data-discovery-and-detection/action-center/ClassificationReportModal.tsx`
around lines 49 - 59, getCategoryColor currently calls category.toLowerCase()
without guarding for undefined/null which can crash when items have optional
category; update getCategoryColor to first coerce or guard the incoming category
(e.g., treat undefined/null as "unknown" or an empty string) before calling
toLowerCase, then look up the colors map (advertising, analytics, social_media,
functional, essential, unknown) and return the default tag when no match; ensure
the function signature and callers (getCategoryColor) handle optional string
input safely.

Comment on lines +627 to +631
const count = selectedUrns.length > 0 ? selectedUrns.length : "all";
toast(
successToastParams(
`Classification complete for ${count} uncategorized assets.`,
`Confirmed`,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid “complete” wording if classification is async/queued.

The mutation response model is task-based, so Line 630 can overstate completion. Use “started/queued” messaging to avoid false confirmation.

✏️ Proposed fix
-      const count = selectedUrns.length > 0 ? selectedUrns.length : "all";
+      const count = selectedUrns.length > 0 ? selectedUrns.length : "all";
       toast(
         successToastParams(
-          `Classification complete for ${count} uncategorized assets.`,
+          `Classification started for ${count} uncategorized assets.`,
           `Confirmed`,
         ),
       );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const count = selectedUrns.length > 0 ? selectedUrns.length : "all";
toast(
successToastParams(
`Classification complete for ${count} uncategorized assets.`,
`Confirmed`,
const count = selectedUrns.length > 0 ? selectedUrns.length : "all";
toast(
successToastParams(
`Classification started for ${count} uncategorized assets.`,
`Confirmed`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/admin-ui/src/features/data-discovery-and-detection/action-center/hooks/useDiscoveredAssetsTable.tsx`
around lines 627 - 631, The toast message in useDiscoveredAssetsTable.tsx
currently states "Classification complete..." but the mutation is
task-based/async; update the message passed to successToastParams (where toast
is called with selectedUrns and successToastParams) to reflect that the
operation was started/queued (e.g., "Classification started for {count}
uncategorized assets." or "Classification queued for {count} uncategorized
assets.") so it doesn't imply immediate completion.

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.

2 participants