Back to Source Monitor

Sources Index Scrape Recommendation Badge

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

0.13.04.0 KB
Original Source

Plan 03: Sources Index Scrape Recommendation Badge

Overview

Add a visual indicator badge on source rows in the sources index that flags sources as scrape candidates (low avg feed word count, scraping not enabled). Uses pre-computed data already available in the controller.


Task 1: Compute scrape candidate IDs in SourcesController#index

Files:

  • app/controllers/source_monitor/sources_controller.rb

Description: In the index action, after computing @avg_feed_word_counts, compute the set of scrape candidate source IDs for the current page. Use the already-loaded @avg_feed_word_counts hash and threshold config to determine candidates without extra queries:

ruby
@scrape_recommendation_threshold = SourceMonitor.config.scraping.scrape_recommendation_threshold
@scrape_candidate_ids = compute_scrape_candidate_ids(source_ids)

Add private method:

ruby
def compute_scrape_candidate_ids(source_ids)
  return Set.new if source_ids.empty?

  threshold = SourceMonitor.config.scraping.scrape_recommendation_threshold
  return Set.new if threshold.nil? || threshold <= 0

  # Use already-loaded avg_feed_word_counts + check scraping_enabled from loaded sources
  candidate_ids = @sources.select do |source|
    avg = @avg_feed_word_counts[source.id]
    avg.present? && avg < threshold && !source.scraping_enabled?
  end.map(&:id)

  Set.new(candidate_ids)
end

Pass scrape_candidate_ids to the row partial via locals.

Tests:

  • test/controllers/source_monitor/sources_controller_test.rb -- Add test for:
    • @scrape_candidate_ids is assigned as a Set
    • Sources below threshold with scraping disabled are included
    • Sources above threshold are excluded

Task 2: Add scrape recommendation badge to source row partial

Files:

  • app/views/source_monitor/sources/_row.html.erb

Description: Add a badge next to the source name (after the existing "Blocked" badge) when the source is a scrape candidate. Use the scrape_candidate_ids local:

erb
<% scrape_candidates = local_assigns[:scrape_candidate_ids] || Set.new %>
<% if scrape_candidates.include?(source.id) %>
  <span class="inline-flex items-center rounded-full bg-violet-100 px-2 py-0.5 text-[10px] font-semibold text-violet-700"
        title="Low feed word count — consider enabling scraping"
        data-testid="scrape-recommendation-badge">
    Scrape Recommended
  </span>
<% end %>

Place this badge in the existing flex items-center gap-2 div alongside the source name and blocked badge.

Tests:

  • test/system/sources_test.rb or integration test -- Assert badge appears for candidate sources and not for non-candidates

Task 3: Update sources index to pass candidate IDs to row partial

Files:

  • app/views/source_monitor/sources/index.html.erb

Description: Update the render partial: "source_monitor/sources/row" call to include scrape_candidate_ids in locals:

erb
<%= render partial: "source_monitor/sources/row",
      collection: @sources,
      as: :source,
      locals: {
        item_activity_rates: @item_activity_rates,
        avg_feed_word_counts: @avg_feed_word_counts,
        avg_scraped_word_counts: @avg_scraped_word_counts,
        search_params: @search_params,
        scrape_candidate_ids: @scrape_candidate_ids
      } %>

Tests:

  • Covered by Task 2 system/integration test

Task 4: Add avg_feed_words_lt filter label to sources index filter banner

Files:

  • app/views/source_monitor/sources/index.html.erb

Description: When the dashboard widget links to sources with avg_feed_words_lt filter, the sources index should display a filter banner pill showing the active filter. Add avg_feed_words_lt to the dropdown_filter_keys array and add a filter label for it:

In the filter_labels hash, add:

ruby
"avg_feed_words_lt" => "Avg Feed Words: < #{@search_params['avg_feed_words_lt']}"

Also add to the dropdown_filter_keys array so it shows as an active filter pill.

Tests:

  • Integration test: visit sources index with q[avg_feed_words_lt]=200 and assert filter pill is rendered