lite-reader icon indicating copy to clipboard operation
lite-reader copied to clipboard

Phase 2: Refactor feed management from jQuery to HTMX

Open Copilot opened this issue 1 month ago • 0 comments

Migrates feed add/list/delete operations from jQuery AJAX to HTMX while preserving JSON API backward compatibility. Backend now detects HTMX requests via HX-Request header and returns HTML fragments; non-HTMX requests still receive JSON.

Backend Changes

  • New fragment renderer (fragments_feed.go):

    • renderFeedRow() - Single feed HTML
    • renderFeedList() - Complete list including static Unread/Starred feeds
    • renderFeedError() - Error message fragments
  • Dual-mode handlers (feed.go):

    func (h *Router) addFeed(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
        // ... validation ...
    
        if isHTMXRequest(r) {
            feeds, _ := h.feedService.ListFeeds(userID)
            w.Header().Set("Content-Type", "text/html; charset=utf-8")
            w.WriteHeader(http.StatusCreated)
            _, _ = w.Write([]byte(renderFeedList(feeds)))
            return
        }
    
        // JSON response for non-HTMX
        w.WriteHeader(http.StatusCreated)
        json.NewEncoder(w).Encode(toAddFeedResponse(t))
    }
    
  • Form data support (model.go): Handlers now accept both application/json and application/x-www-form-urlencoded

Frontend Changes

  • HTMX form (index.html):

    <form hx-post="/feeds" hx-target="#feeds-list" hx-swap="innerHTML">
        <input type="text" name="url" required />
    </form>
    
  • Removed jQuery AJAX (feeds.js): Replaced $.ajax() calls with HTMX for add/delete, vanilla fetch() for reads

  • Auth configuration (main.js):

    htmx.on('htmx:configRequest', function(evt) {
        const token = getAuthToken();
        if (token) evt.detail.headers['Authorization'] = 'Bearer ' + token;
    });
    

Known Issue

⚠️ HTMX auth header configuration timing issue causing 401 errors in tests. Event listener registers but may not fire before initial requests. Requires alternative approach (meta tags, pre-config, or extension).

Testing

Updated MainPage.js to submit form via Enter key instead of double-click pattern. Backend unit tests pass. UI tests blocked by auth issue above.

Original prompt

Phase 2: Refactor Feed Management with HTMX (No htmx-go)

Refactor the feed management portion of the application to eliminate all jQuery / jQuery-UI usage and migrate interactions to HTMX while preserving existing JSON API behavior for non-HTMX requests. This phase focuses ONLY on feed-related functionality and must maintain full test parity (Playwright feed tests) and code quality (lint passes). Do NOT integrate htmx-go; use the existing backend architecture (httprouter handlers, middleware chain) and manual detection of HTMX via the HX-Request header.

Scope

  • Add feed form submission
  • Feed listing display
  • Refresh / fetch new items for a feed
  • Empty feed states
  • Feed deletion (if present)
  • Updating unread counts / status indicators related to feeds

Constraints & Principles

  • No introduction of new backend libraries for HTMX response handling.
  • Detect HTMX requests with: isHTMX := r.Header.Get("HX-Request") == "true".
  • For HTMX requests: return minimal HTML fragments (only what needs updating).
  • For non-HTMX requests: preserve existing JSON responses (backward compatibility).
  • Remove ALL jQuery and jQuery-UI code related to feeds.
  • Avoid adding large custom JavaScript; prefer HTMX attributes. Any JS > 3 lines must live in public/js/feeds.js.
  • Maintain existing CSS classes / IDs used by Playwright tests (or update tests if unavoidable, but prefer not to break selectors).
  • Ensure all Playwright feed tests pass after changes.
  • Run make lint after backend changes and fix all issues.

Backend Tasks

  1. In internal/infra/http/api/feed.go (and any related handlers):
    • Wrap logic with HTMX detection.
    • For HTMX requests return Content-Type: text/html; charset=utf-8 and write fragment HTML only.
    • Provide helper functions (can be added in a new file internal/infra/http/api/fragments_feed.go) such as:
      • renderFeedRow(f *feed.Feed) string
      • renderFeedList(feeds []*feed.Feed) string
      • renderFeedStatus(msg string, kind string) string (kind = success|error)
    • Ensure error paths return small HTML fragments for HTMX (e.g., a <div class="feed-error">...</div>).
    • Preserve JSON response logic if !isHTMX.
  2. Support feed refresh endpoint to return only updated feed row fragment or status fragment when HTMX is used.
  3. Feed deletion: return a fragment that removes/updates the list (e.g., updated list or a status message). Consider using hx-swap strategies; if removal causes an empty list, return an empty state fragment.
  4. Make sure handlers still respect middleware (auth, content type for JSON in non-HTMX mode). For HTMX responses override content-type manually.
  5. Keep existing models / response structs for JSON path untouched.

Frontend Tasks (public/ directory)

  1. Locate and remove jQuery-based feed scripts (DOM selection, AJAX calls, event binding) associated with feed management.
  2. Modify feed add form:
    • Add hx-post="/feeds".
    • Add hx-target="#feeds-list" (or appropriate container ID).
    • Add hx-swap="innerHTML" (or suitable strategy).
    • Add loading indicator: set up element with id="feed-add-indicator" and include hx-indicator="#feed-add-indicator" on the form.
  3. Refresh buttons/links for feeds:
    • Add hx-put="/feeds/{id}/fetch" with dynamic ID.
    • Target only the feed row container: hx-target="#feed-row-{id}".
    • Swap strategy: hx-swap="outerHTML" to replace the entire row.
  4. Delete feed action:
    • Use hx-delete="/feeds/{id}".
    • hx-target="#feeds-list" with server returning a new list or status fragment.
  5. Empty state handling:
    • If list becomes empty, server returns an <div class="feed-empty">No feeds added yet</div> fragment.
  6. Add/Update public/js/feeds.js ONLY if logic > 3 lines is needed (e.g., small utility for progressive enhancement). Keep it minimal and documented.

HTML / Fragment Guidelines

  • Fragments must be valid, minimal HTML (no full <html> / <body> wrappers).
  • Each feed row should have stable identifiers: e.g., <div id="feed-row-{{.ID}}" class="feed-row"> for targeting.
  • Avoid changing existing test selectors unless absolutely required.

Testing Requirements

  • Run npm run test:ui tests/ui/feeds.spec.js (or make test-ui) after changes; MUST pass 100%.
  • If selectors change, update Page Object files (tests/ui/pages/) consistently.
  • Manually verify: RSS & Atom feed addition, refresh, item display, empty feed scenario.

Linting & Quality

  • Run make lint after backend modifications; resolve all issues.
  • Run go mod tidy only if imports were added/removed (expect no new module for HTMX server handling).

Deliverables

  • Updated Go handlers with HTMX conditional fragment responses.
  • New helper fragment rendering functions (if added).
  • Updated HTML templates/forms using HTMX attributes.
  • Removal of feed-related jQuery code.
  • Optional public/js/feeds.js (only if >3 lines of JS needed) with inline comments explaining necessity.
  • Pas...

This pull request was created as a result of the following prompt from Copilot chat.

Phase 2: Refactor Feed Management with HTMX (No htmx-go)

Refactor the feed management portion of the application to eliminate all jQuery / jQuery-UI usage and migrate interactions to HTMX while preserving existing JSON API behavior for non-HTMX requests. This phase focuses ONLY on feed-related functionality and must maintain full test parity (Playwright feed tests) and code quality (lint passes). Do NOT integrate htmx-go; use the existing backend architecture (httprouter handlers, middleware chain) and manual detection of HTMX via the HX-Request header.

Scope

  • Add feed form submission
  • Feed listing display
  • Refresh / fetch new items for a feed
  • Empty feed states
  • Feed deletion (if present)
  • Updating unread counts / status indicators related to feeds

Constraints & Principles

  • No introduction of new backend libraries for HTMX response handling.
  • Detect HTMX requests with: isHTMX := r.Header.Get("HX-Request") == "true".
  • For HTMX requests: return minimal HTML fragments (only what needs updating).
  • For non-HTMX requests: preserve existing JSON responses (backward compatibility).
  • Remove ALL jQuery and jQuery-UI code related to feeds.
  • Avoid adding large custom JavaScript; prefer HTMX attributes. Any JS > 3 lines must live in public/js/feeds.js.
  • Maintain existing CSS classes / IDs used by Playwright tests (or update tests if unavoidable, but prefer not to break selectors).
  • Ensure all Playwright feed tests pass after changes.
  • Run make lint after backend changes and fix all issues.

Backend Tasks

  1. In internal/infra/http/api/feed.go (and any related handlers):
    • Wrap logic with HTMX detection.
    • For HTMX requests return Content-Type: text/html; charset=utf-8 and write fragment HTML only.
    • Provide helper functions (can be added in a new file internal/infra/http/api/fragments_feed.go) such as:
      • renderFeedRow(f *feed.Feed) string
      • renderFeedList(feeds []*feed.Feed) string
      • renderFeedStatus(msg string, kind string) string (kind = success|error)
    • Ensure error paths return small HTML fragments for HTMX (e.g., a <div class="feed-error">...</div>).
    • Preserve JSON response logic if !isHTMX.
  2. Support feed refresh endpoint to return only updated feed row fragment or status fragment when HTMX is used.
  3. Feed deletion: return a fragment that removes/updates the list (e.g., updated list or a status message). Consider using hx-swap strategies; if removal causes an empty list, return an empty state fragment.
  4. Make sure handlers still respect middleware (auth, content type for JSON in non-HTMX mode). For HTMX responses override content-type manually.
  5. Keep existing models / response structs for JSON path untouched.

Frontend Tasks (public/ directory)

  1. Locate and remove jQuery-based feed scripts (DOM selection, AJAX calls, event binding) associated with feed management.
  2. Modify feed add form:
    • Add hx-post="/feeds".
    • Add hx-target="#feeds-list" (or appropriate container ID).
    • Add hx-swap="innerHTML" (or suitable strategy).
    • Add loading indicator: set up element with id="feed-add-indicator" and include hx-indicator="#feed-add-indicator" on the form.
  3. Refresh buttons/links for feeds:
    • Add hx-put="/feeds/{id}/fetch" with dynamic ID.
    • Target only the feed row container: hx-target="#feed-row-{id}".
    • Swap strategy: hx-swap="outerHTML" to replace the entire row.
  4. Delete feed action:
    • Use hx-delete="/feeds/{id}".
    • hx-target="#feeds-list" with server returning a new list or status fragment.
  5. Empty state handling:
    • If list becomes empty, server returns an <div class="feed-empty">No feeds added yet</div> fragment.
  6. Add/Update public/js/feeds.js ONLY if logic > 3 lines is needed (e.g., small utility for progressive enhancement). Keep it minimal and documented.

HTML / Fragment Guidelines

  • Fragments must be valid, minimal HTML (no full <html> / <body> wrappers).
  • Each feed row should have stable identifiers: e.g., <div id="feed-row-{{.ID}}" class="feed-row"> for targeting.
  • Avoid changing existing test selectors unless absolutely required.

Testing Requirements

  • Run npm run test:ui tests/ui/feeds.spec.js (or make test-ui) after changes; MUST pass 100%.
  • If selectors change, update Page Object files (tests/ui/pages/) consistently.
  • Manually verify: RSS & Atom feed addition, refresh, item display, empty feed scenario.

Linting & Quality

  • Run make lint after backend modifications; resolve all issues.
  • Run go mod tidy only if imports were added/removed (expect no new module for HTMX server handling).

Deliverables

  • Updated Go handlers with HTMX conditional fragment responses.
  • New helper fragment rendering functions (if added).
  • Updated HTML templates/forms using HTMX attributes.
  • Removal of feed-related jQuery code.
  • Optional public/js/feeds.js (only if >3 lines of JS needed) with inline comments explaining necessity.
  • Passing Playwright feed tests.
  • Lint-clean codebase for modified files.

Success Criteria

  • All jQuery/jQuery-UI feed code removed.
  • HTMX attributes drive feed interactions.
  • HTML fragment responses implemented for HTMX paths; JSON preserved otherwise.
  • All feed Playwright tests pass.
  • make lint produces zero errors.
  • Minimal, organized JavaScript (none or small dedicated file).
  • No regression in existing feed functionality.

Non-Goals (Phase 2)

  • Do not refactor authentication, items, or UI components (covered in other phases).
  • Do not introduce htmx-go or other response abstraction libraries.
  • Do not alter database or domain logic.

Proceed to implement and open a pull request with these changes.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot avatar Nov 16 '25 21:11 Copilot