Skip to content

Conversation

@glauberlima
Copy link

Closes #8101.

Overview

This PR adds automatic filter name fetching when users add custom blocklists or allowlists. Instead of manually typing both URL and name, users can now paste the filter URL and have the name auto-populated from the filter's metadata.

Implementation

Backend:

  • New endpoint: POST /control/filtering/fetch_title
  • Validates URLs with permissive rules (allows extension-less paths like /hosts)
  • Extracts title from filter metadata using existing rulelist.Parser
  • Downloads only first 4KB for performance

Frontend:

  • Monitors URL field changes with 800ms debounce
  • Shows loading state while fetching
  • Auto-populates name field only when empty (never overwrites user input)
  • Silent error handling (no intrusive messages)

Testing:

  • ✅ 13 backend test cases covering validation and extraction
  • ✅ All linters pass
  • ✅ Manual testing completed

Screenshots

AdGuard Home - Google Chrome 2025-11-14 08-19-03

Breaking Changes

None. This is a purely additive feature with graceful degradation.

Add endpoint to fetch blocklist/allowlist titles automatically from URLs.
Frontend includes 800ms debounce, respects user input, and has debug logging.
Backend includes permissive validation for URLs without file extensions.
Copy link

@windsurf-bot windsurf-bot bot left a comment

Choose a reason for hiding this comment

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

Other comments (2)
  • internal/filtering/http.go (64-99) This function duplicates significant portions of `validateFilterURL`. Consider refactoring to extract common validation logic into a shared helper function to avoid future maintenance issues.
  • internal/filtering/http.go (681-681) The error message format is inconsistent with other handlers. Consider using lowercase for consistency:
    			"failed to parse request body json: %s",
    

💡 To request another review, post a new comment with "/windsurf-review".

debounceTimerRef.current = setTimeout(async () => {
setIsFetchingTitle(true);
try {
const title = await dispatch(fetchFilterTitle(urlValue) as any);
Copy link

Choose a reason for hiding this comment

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

Using as any bypasses TypeScript's type checking, which can hide potential errors. Consider properly typing the fetchFilterTitle action return value or using a more specific type assertion that preserves some type safety.

// - Name field already has a value (user has typed something)
// - We're in edit mode (initialValues provided)
// - URL doesn't pass basic validation
if (!urlValue || nameValue || initialValues?.name) {
Copy link

Choose a reason for hiding this comment

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

The dependency array includes initialValues, but the condition only checks initialValues?.name. Consider either checking the entire initialValues object in the condition or only including initialValues?.name in the dependency array for consistency.

Comment on lines +629 to +632
p := rulelist.NewParser()
res, err := p.Parse(io.Discard, lr, *bufPtr)
if err != nil {
return "", fmt.Errorf("parsing filter: %w", err)
Copy link

Choose a reason for hiding this comment

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

The function downloads and parses the entire filter content (up to 4KB) even though we only need the title. Consider adding a method to rulelist.Parser that can extract just the title without parsing all rules, which would be more efficient.

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.

Feature: Auto-fetch filter names from URL when adding custom blocklists/allowlists

1 participant