Skip to content

Phase 2: Refactor feed management from jQuery to HTMX#34

Draft
Copilot wants to merge 8 commits intomasterfrom
copilot/refactor-feed-management-htmx
Draft

Phase 2: Refactor feed management from jQuery to HTMX#34
Copilot wants to merge 8 commits intomasterfrom
copilot/refactor-feed-management-htmx

Conversation

Copy link
Contributor

Copilot AI commented Nov 16, 2025

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 AI and others added 3 commits November 16, 2025 21:16
Co-authored-by: cubny <172368+cubny@users.noreply.github.com>
Co-authored-by: cubny <172368+cubny@users.noreply.github.com>
Co-authored-by: cubny <172368+cubny@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor feed management to use HTMX without jQuery Phase 2: Refactor feed management from jQuery to HTMX Nov 16, 2025
Copilot AI requested a review from cubny November 16, 2025 21:36
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