Skip to content

fix: resolve merge conflict markers in leads.html#301

Open
bh462007 wants to merge 1 commit into
Kuldeeep18:mainfrom
bh462007:fix/leads-merge-conflicts
Open

fix: resolve merge conflict markers in leads.html#301
bh462007 wants to merge 1 commit into
Kuldeeep18:mainfrom
bh462007:fix/leads-merge-conflicts

Conversation

@bh462007

@bh462007 bh462007 commented Jun 16, 2026

Copy link
Copy Markdown

Related Issue

Closes #278


Summary of Changes

Resolved all unresolved Git merge conflict markers in frontend/leads.html.

While resolving the conflicts, I reviewed both versions of the code and retained the necessary functionality from each side to ensure no features were unintentionally removed.

Changes Made

  • Removed all merge conflict markers (<<<<<<<, =======, >>>>>>>)
  • Merged conflicting HTML and JavaScript sections
  • Preserved the existing filter functionality and import history features
  • Ensured the page structure remains intact and functional

Type of Change

  • Bug fix

Testing

Steps performed:

  1. Verified that all merge conflict markers were removed.
  2. Checked the HTML structure after resolving conflicts.
  3. Opened the page in a browser and confirmed that the layout renders correctly.
  4. Verified that the filter panel, sidebar, header, and CSV import section are present and functioning as expected.

Note: Features that depend on backend APIs could not be fully verified without a running backend service.


📸 Screenshots (if applicable)

N/A


Checklist

  • No merge conflict markers remain in the file
  • HTML structure remains valid after resolution
  • Page renders correctly in the browser
  • Existing functionality from both conflicting versions has been preserved
  • No merge conflicts with the target branch
  • Related issue linked

Summary by CodeRabbit

Release Notes

  • New Features

    • Redesigned Leads page layout with improved separation between Import History and Leads tables.
    • Enhanced filter panel organization with active filter indicators and summary chips.
  • Bug Fixes

    • Refined empty state messaging for leads and import errors.
    • Improved import error row display and messaging.

Copilot AI review requested due to automatic review settings June 16, 2026 18:53
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

frontend/leads.html is restructured in both markup and inline script. The filter panel, active-filter chips, and table section order (Import History before Leads) are rearranged. The inline script consolidates tag color logic, refines lead/import-error/history rendering, refactors filter parameter and indicator UI, introduces explicit loader functions, reorganizes the bootstrap sequence, and changes CSV upload 202 handling to a timed full-page reload. Merge-conflict markers are removed.

Changes

Leads Page UI and Script Refactor

Layer / File(s) Summary
Page layout: header, filter panel, table sections, modal marker
frontend/leads.html
Rearranges breadcrumb and search area, restructures the hidden filter panel (tag/date/status controls, action buttons, active-filter chip row inside the panel), reorders table sections so Import History precedes the Leads table, and adds the Import Errors Modal section marker.
Client state, tag contrast color, and timestamp helper
frontend/leads.html
Refactors inline script state declarations, consolidates tag color contrast via a new contrastColor helper used by tag badge rendering, and adds/updates the formatTimestamp helper for import job display.
Leads, import-error, and import-history rendering
frontend/leads.html
Updates import-error row rendering to show a "no row-level errors" message when appropriate, refines the leads-table empty state, updates lead row output and clipboard-email event wiring, and conditionally renders a "View" button vs "None" in import-history rows based on failed_count.
Filter parameter construction and active-filter indicator UI
frontend/leads.html
Refactors how filter parameters are built from tag/date/status UI controls, updates active-filter indicator dot and summary chip generation, and reorders applyFilters and clearFilters flow.
Data loader functions and DOMContentLoaded bootstrap
frontend/leads.html
Introduces dedicated loadLeads and loadImportHistory functions replacing prior inline loading logic; reorganizes DOMContentLoaded to load data, then tags, then register event handlers for search, history refresh, and filter panel toggle.
CSV upload 202 handling: timed page reload
frontend/leads.html
Changes the CSV upload form success path on HTTP 202 to schedule a full page reload after a delay instead of refreshing tables in-place; failure/error handling and button re-enable are retained. Removes merge-conflict markers and closes final HTML correctly.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • #298: The PR explicitly removes leftover merge-conflict markers from frontend/leads.html, which is the exact blocking bug described in that issue (raw <<<<<<< HEAD / ======= / >>>>>>> upstream/main markers corrupting the DOM).

Poem

🐇 The conflict markers caused such a fuss,
HEAD and upstream were fighting for us.
Now the filters chip in, history shows first,
A timed reload quenches the CSV thirst.
The bunny hops through a layout so neat—
Clean HTML makes the harvest complete! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change - resolving merge conflict markers in leads.html, which aligns with the PR objective and linked issue.
Linked Issues check ✅ Passed The PR successfully addresses issue #278 by removing merge conflict markers and restoring proper HTML/JavaScript structure in leads.html.
Out of Scope Changes check ✅ Passed All changes are within scope - the PR focuses solely on resolving merge conflicts while preserving functionality without introducing unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR resolves merge-conflict artifacts in leads.html and adds UI + logic for viewing CSV import history details, including an import error log modal.

Changes:

  • Removes leftover merge markers/conflict noise and normalizes the layout/whitespace.
  • Adds an “Import Errors” modal and client-side rendering for row-level import error logs.
  • Introduces import history state (allImportJobs) and wiring for “View” error buttons.
Comments suppressed due to low confidence (2)

frontend/leads.html:1

  • Untrusted server-provided values are interpolated into innerHTML without escaping (entry.field, entry.message, and job.filename). This is a concrete XSS vector if any of those fields can contain HTML. Use escapeHtml(...) on these values (or build the rows with textContent/DOM APIs) before inserting into the DOM.
<!DOCTYPE html>

frontend/leads.html:577

  • Untrusted server-provided values are interpolated into innerHTML without escaping (entry.field, entry.message, and job.filename). This is a concrete XSS vector if any of those fields can contain HTML. Use escapeHtml(...) on these values (or build the rows with textContent/DOM APIs) before inserting into the DOM.
            tbody.innerHTML = jobs.map(job => `
                <tr>
                    <td class="fw-semibold">${job.filename}</td>
                    <td>${job.total_rows ?? 0}</td>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/leads.html
Comment on lines 510 to 517
function openImportErrors(jobId) {
const job = allImportJobs.find(item => item.id === jobId);
if (!job) return;

document.getElementById('import-errors-meta').textContent =
`${job.filename} · ${job.failed_count} error${job.failed_count === 1 ? '' : 's'}`;
renderImportErrorRows(job);
bootstrap.Modal.getOrCreateInstance(document.getElementById('importErrorsModal')).show();
}
Comment thread frontend/leads.html
Comment on lines 588 to 590
document.querySelectorAll('.view-import-errors-btn').forEach(btn => {
btn.addEventListener('click', () => openImportErrors(btn.dataset.jobId));
});

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/leads.html (2)

731-745: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Don’t leave infinite loading UI on failed data loads.

Line 733 and Line 741 return silently on non-OK responses, so both tables can stay stuck on spinner rows with no recovery hint.

Suggested fix
         async function loadLeads() {
-            const res = await fetchWithAuth('/leads/');
-            if (!res.ok) return;
-            allLeads = await res.json();
-            renderStats(allLeads);
-            renderLeadRows(allLeads);
+            const tbody = document.getElementById('leads-table-body');
+            const res = await fetchWithAuth('/leads/');
+            if (!res.ok) {
+                tbody.innerHTML = '<tr><td colspan="7" class="text-center py-4 text-danger">Failed to load leads.</td></tr>';
+                return;
+            }
+            allLeads = await res.json();
+            renderStats(allLeads);
+            renderLeadRows(allLeads);
         }
@@
         async function loadImportHistory() {
-            const res = await fetchWithAuth('/lead-import-jobs/');
-            if (!res.ok) return;
+            const tbody = document.getElementById('import-history-body');
+            const res = await fetchWithAuth('/lead-import-jobs/');
+            if (!res.ok) {
+                tbody.innerHTML = '<tr><td colspan="6" class="text-center py-4 text-danger">Failed to load import history.</td></tr>';
+                return;
+            }
             const payload = await res.json();
             allImportJobs = Array.isArray(payload) ? payload : (payload.results || []);
             renderImportHistory(allImportJobs);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/leads.html` around lines 731 - 745, Both the loadLeads() and
loadImportHistory() functions silently return when the fetch response is not OK,
leaving loading spinners visible indefinitely with no error feedback to the
user. Instead of silently returning on failed responses, add proper error
handling to both functions that updates the UI to display an error state or
message. This ensures users are informed when data loading fails rather than
being left with an unresponsive loading state.

501-507: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Escape API/user-provided values before injecting HTML.

Line 504–506 and Line 576 interpolate unescaped values into innerHTML (entry.email, entry.error, job.filename). That is a stored-XSS path if CSV/input payloads are reflected by the backend.

Suggested fix
         function renderImportErrorRows(job) {
             const tbody = document.getElementById('import-errors-body');
             const errors = Array.isArray(job?.error_log) ? job.error_log : [];
@@
             tbody.innerHTML = errors.map(entry => `
                 <tr>
-                    <td class="fw-semibold">${entry.row ?? '-'}</td>
-                    <td>${entry.email || '<span class="text-muted">-</span>'}</td>
-                    <td>${entry.error || '<span class="text-muted">-</span>'}</td>
+                    <td class="fw-semibold">${escapeHtml(entry.row ?? '-')}</td>
+                    <td>${entry.email ? escapeHtml(entry.email) : '<span class="text-muted">-</span>'}</td>
+                    <td>${entry.error ? escapeHtml(entry.error) : '<span class="text-muted">-</span>'}</td>
                 </tr>
             `).join('');
         }
@@
             tbody.innerHTML = jobs.map(job => `
                 <tr>
-                    <td class="fw-semibold">${job.filename}</td>
+                    <td class="fw-semibold">${escapeHtml(job.filename)}</td>
                     <td>${job.total_rows ?? 0}</td>

Also applies to: 574-577

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/leads.html` around lines 501 - 507, The code is vulnerable to
stored-XSS attacks by injecting unescaped user-provided values directly into
innerHTML. Create a utility function to escape HTML special characters
(converting &, <, >, ", and ' to their HTML entity equivalents), then apply this
escaping function to all user-controlled values before injecting them:
entry.row, entry.email, and entry.error in the first location, and job.filename
in the second location. Replace the direct template literal interpolation of
these variables with calls to the HTML-escaping function to prevent malicious
content from being executed as JavaScript.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/leads.html`:
- Around line 510-512: The ID comparison in the openImportErrors function at
line 511 uses strict equality (===) to match item.id against jobId, but these
values may have different types (one could be a string while the other is
numeric), causing the lookup to fail intermittently. Convert both the item.id
and jobId to the same type before comparison, such as by converting both to
strings using String() or by converting both to numbers. Apply this same fix to
the second occurrence of this pattern at lines 588-590, ensuring consistent type
conversion is used in both locations for reliable ID matching.

---

Outside diff comments:
In `@frontend/leads.html`:
- Around line 731-745: Both the loadLeads() and loadImportHistory() functions
silently return when the fetch response is not OK, leaving loading spinners
visible indefinitely with no error feedback to the user. Instead of silently
returning on failed responses, add proper error handling to both functions that
updates the UI to display an error state or message. This ensures users are
informed when data loading fails rather than being left with an unresponsive
loading state.
- Around line 501-507: The code is vulnerable to stored-XSS attacks by injecting
unescaped user-provided values directly into innerHTML. Create a utility
function to escape HTML special characters (converting &, <, >, ", and ' to
their HTML entity equivalents), then apply this escaping function to all
user-controlled values before injecting them: entry.row, entry.email, and
entry.error in the first location, and job.filename in the second location.
Replace the direct template literal interpolation of these variables with calls
to the HTML-escaping function to prevent malicious content from being executed
as JavaScript.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 91482a34-b420-447a-8670-e2f60266dd0b

📥 Commits

Reviewing files that changed from the base of the PR and between 90052f9 and c7069fc.

📒 Files selected for processing (1)
  • frontend/leads.html

Comment thread frontend/leads.html
Comment on lines 510 to 512
function openImportErrors(jobId) {
const job = allImportJobs.find(item => item.id === jobId);
if (!job) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use type-stable ID matching for import job lookup.

Line 511 compares item.id === jobId; dataset.jobId is a string, while API IDs are often numeric. That can make the “View” button no-op intermittently.

Suggested fix
         function openImportErrors(jobId) {
-            const job = allImportJobs.find(item => item.id === jobId);
+            const job = allImportJobs.find(item => String(item.id) === String(jobId));
             if (!job) return;

Also applies to: 588-590

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/leads.html` around lines 510 - 512, The ID comparison in the
openImportErrors function at line 511 uses strict equality (===) to match
item.id against jobId, but these values may have different types (one could be a
string while the other is numeric), causing the lookup to fail intermittently.
Convert both the item.id and jobId to the same type before comparison, such as
by converting both to strings using String() or by converting both to numbers.
Apply this same fix to the second occurrence of this pattern at lines 588-590,
ensuring consistent type conversion is used in both locations for reliable ID
matching.

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.

LO-050 [Easy - Bug]: Unresolved Git Merge Conflict Markers in leads.html

2 participants