Back to Source Monitor

Dashboard Scrape Recommendations Widget

.vbw-planning/milestones/ui-fixes-and-smart-scraping/phases/04-smart-scrape-recommendations/04-PLAN-02.md

0.13.03.5 KB
Original Source

Plan 02: Dashboard Scrape Recommendations Widget

Overview

Add a dashboard widget card that shows the count of sources recommended for scraping (low avg feed word count, scraping not yet enabled). Links to the sources index filtered to show only candidates.


Task 1: Add scrape_recommendations to StatsQuery

Files:

  • lib/source_monitor/dashboard/queries/stats_query.rb

Description: Add scrape_candidates_count to the stats hash returned by StatsQuery#call. Use SourceMonitor::Analytics::ScrapeRecommendations to compute the count.

Add to the returned hash:

ruby
scrape_candidates_count: scrape_candidates_count

Add private method:

ruby
def scrape_candidates_count
  SourceMonitor::Analytics::ScrapeRecommendations.new.candidates_count
end

Tests:

  • Update existing StatsQuery tests in test/lib/source_monitor/dashboard/ (or create if not present) to assert scrape_candidates_count is returned

Task 2: Create dashboard scrape recommendations widget partial

Files:

  • app/views/source_monitor/dashboard/_scrape_recommendations.html.erb

Description: Create a widget partial that follows the existing dashboard card pattern (bordered card with header + divider + content). Only render content when scrape_candidates_count > 0.

Widget should display:

  • Title: "Scrape Recommendations"
  • Subtitle: "Sources with low feed word counts"
  • Count of candidate sources (large number like stat cards)
  • Brief description: "sources could benefit from scraping"
  • Link button: "View Candidates" linking to sources index with Ransack filter for avg_feed_words below threshold

The filter link should use: source_monitor.sources_path(q: { avg_feed_words_lt: threshold, scraping_enabled_eq: false, active_eq: true })

Use the same Tailwind card pattern as the Quick Actions widget:

erb
<div class="rounded-lg border border-slate-200 bg-white shadow-sm">
  <div class="border-b border-slate-200 px-5 py-4">
    <h2 class="text-lg font-medium">Scrape Recommendations</h2>
    <p class="mt-1 text-xs text-slate-500">Sources with low feed word counts.</p>
  </div>
  <div class="px-5 py-4">
    ...count and link...
  </div>
</div>

Tests:

  • None for partials directly (covered by integration/system tests)

Task 3: Wire widget into dashboard index

Files:

  • app/controllers/source_monitor/dashboard_controller.rb
  • app/views/source_monitor/dashboard/index.html.erb

Description: In the controller, compute and assign @scrape_candidates_count:

ruby
@scrape_candidates_count = queries.stats[:scrape_candidates_count]
@scrape_recommendation_threshold = SourceMonitor.config.scraping.scrape_recommendation_threshold

In the view, render the widget in the right sidebar column (after job_metrics, before Quick Actions) only when count > 0:

erb
<%= render "scrape_recommendations",
      count: @scrape_candidates_count,
      threshold: @scrape_recommendation_threshold if @scrape_candidates_count.to_i > 0 %>

Tests:

  • test/controllers/source_monitor/dashboard_controller_test.rb -- Add test for:
    • Dashboard index renders successfully (existing test should still pass)
    • @scrape_candidates_count is assigned

Task 4: Add scraping_enabled to Source ransackable_attributes

Files:

  • app/models/source_monitor/source.rb

Description: Add scraping_enabled to the ransackable_attributes array so the dashboard widget link can filter by scraping_enabled_eq: false. It's a boolean column already on the sources table.

Tests:

  • Assert scraping_enabled is in Source.ransackable_attributes