Skip to content

feat: implement boundary-aware PDF slicing and tighten report template prose#678

Merged
ngoiyaeric merged 2 commits into
mainfrom
pdf-boundary-aware-slicing-and-prose-cleanup-17795820845734913689
Jun 26, 2026
Merged

feat: implement boundary-aware PDF slicing and tighten report template prose#678
ngoiyaeric merged 2 commits into
mainfrom
pdf-boundary-aware-slicing-and-prose-cleanup-17795820845734913689

Conversation

@ngoiyaeric

@ngoiyaeric ngoiyaeric commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator
  • Add data-pdf-nosplit markers to key images in Section 01 and 02 of the report template.
  • Implement a boundary-aware slicing loop in generatePDFReport that prevents splitting protected elements across pages.
  • Normalize Markdown content by collapsing redundant newlines and trimming whitespace.
  • Implement a custom p renderer for ReactMarkdown to skip empty paragraphs.
  • Tighten paragraph spacing with prose-p:my-1 Tailwind utilities.

PR created automatically by Jules for task 17795820845734913689 started by @ngoiyaeric

Summary by CodeRabbit

  • Bug Fixes
    • Improved markdown rendering in reports by removing extra blank lines and skipping empty paragraphs.
    • Reduced awkward spacing in report sections for cleaner, more readable output.
    • Updated PDF generation to keep important images and content from being split across pages when possible.
    • Simplified error handling when a report cannot be generated due to missing page content.

…e prose

- Add data-pdf-nosplit markers to key images in Section 01 and 02 of the report template.
- Implement a boundary-aware slicing loop in generatePDFReport that prevents splitting protected elements across pages.
- Normalize Markdown content by collapsing redundant newlines and trimming whitespace.
- Implement a custom p renderer for ReactMarkdown to skip empty paragraphs.
- Tighten paragraph spacing with prose-p:my-1 Tailwind utilities.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
qcx Ready Ready Preview, Comment Jun 26, 2026 8:05am

@qodo-code-review

Copy link
Copy Markdown
Contributor

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ngoiyaeric, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 27 minutes and 29 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bf614be6-d687-45b2-a21e-ea40b6cb17d7

📥 Commits

Reviewing files that changed from the base of the PR and between b733bb0 and ce6e2cc.

📒 Files selected for processing (1)
  • components/report-template.tsx

Walkthrough

The report template now normalizes markdown, suppresses empty paragraphs, and marks selected images as non-splittable. PDF generation now measures those regions, scales the template, and paginates the rendered output around them.

Changes

Report rendering and PDF layout

Layer / File(s) Summary
Markdown normalization and no-split markers
components/report-template.tsx
aiSummary, response, and resolution_search_result now render normalized markdown with blank paragraphs suppressed, and selected image containers are marked data-pdf-nosplit.
PDF preflight and protected ranges
lib/utils/report-generator.ts
generatePDFReport now logs a shorter missing-element error, waits for image loading, measures template scale, and computes protected ranges from [data-pdf-nosplit] elements.
Protected pagination loop
lib/utils/report-generator.ts
The page loop now tracks currentPosition, avoids cuts through protected ranges when possible, and emits repeated jsPDF.addImage slices with a vertical offset.

Sequence Diagram(s)

sequenceDiagram
  participant generatePDFReport
  participant html2canvas
  participant jsPDF
  generatePDFReport->>generatePDFReport: measure templateRect and protected ranges
  generatePDFReport->>html2canvas: clone the template at templateWidth
  html2canvas->>generatePDFReport: return canvas content
  generatePDFReport->>jsPDF: addImage slices with protected cuts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • QueueLab/QCX#638 — Shares the same report template and PDF pagination path, including the data-pdf-nosplit handling and markdown rendering updates.

Poem

(_/)
(•‿•) I nibbled the blank lines neat and trim,
I tucked the map pages where splits can’t swim.
The PDF hopped on, page by page, just so,
Leaving a trail of tidy markdown glow.

🚥 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 summarizes the main changes: boundary-aware PDF slicing and report template prose cleanup.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pdf-boundary-aware-slicing-and-prose-cleanup-17795820845734913689

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@components/report-template.tsx`:
- Around line 26-30: The normalization in normalizeMarkdown is collapsing all
repeated newlines before parsing, which also alters fenced/preformatted markdown
content and can corrupt code, logs, or intentionally spaced blocks. Update
normalizeMarkdown in report-template.tsx to track whether the parser is inside a
fenced code block and only collapse extra blank lines when outside fences,
keeping the existing downstream ReactMarkdown rendering intact.

In `@lib/utils/report-generator.ts`:
- Around line 35-61: The DOM style mutation in report generation is not
guaranteed to be restored if measurement or protected range collection fails. In
report-generator.ts, wrap the `element.style.width` and `element.style.position`
mutation around the `getBoundingClientRect`/`querySelectorAll` logic in a
`try/finally`, and restore the original inline style in the `finally` block; if
`originalStyle` was empty, remove the `style` attribute instead of setting it
back.
- Around line 100-105: The no-split handling in report generation is still using
the 10px layout buffer, which can split protected elements that start close to
the current position. Update the cut logic in report-generator’s straddle
handling to rely on the loop’s 0.5 progress threshold instead of
`currentPosition + 10`, while keeping the existing `elementHeight <= pdfHeight`
guard, so elements near the next cut are only moved when they actually belong to
the next page.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4fa0b616-bf12-4bb5-8d2b-cb3d1c2a9d93

📥 Commits

Reviewing files that changed from the base of the PR and between e5f1adb and b733bb0.

📒 Files selected for processing (2)
  • components/report-template.tsx
  • lib/utils/report-generator.ts
📜 Review details
🧰 Additional context used
🪛 React Doctor (0.5.8)
components/report-template.tsx

[warning] 188-188: Your users can see & submit the wrong data when this list reorders or filters, so use a stable id like key={item.id}, not the array index "index".

Use a stable id from the item, like key={item.id} or key={item.slug}. Index keys break when the list reorders or filters.

(no-array-index-as-key)


[warning] 188-188: Your users can see & submit the wrong data when this list reorders.

Use a stable key from your data so reordered items keep the right state and DOM.

(no-array-index-key)

🔇 Additional comments (2)
components/report-template.tsx (1)

32-42: LGTM!

Also applies to: 149-149, 216-218, 227-227

lib/utils/report-generator.ts (1)

4-29: LGTM!

Also applies to: 63-79, 81-99, 108-113

Comment on lines +26 to +30
const normalizeMarkdown = (content: string): string => {
return content
.replace(/\n{3,}/g, '\n\n') // Collapse 3+ newlines to 2
.trim()
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid normalizing inside fenced markdown blocks.

Line 28 collapses all 3+ newlines before markdown parsing, including inside fenced/preformatted blocks. That can corrupt report content such as code, logs, or intentionally spaced examples rendered through the downstream ReactMarkdown calls.

Proposed fix
 const normalizeMarkdown = (content: string): string => {
-  return content
-    .replace(/\n{3,}/g, '\n\n') // Collapse 3+ newlines to 2
-    .trim()
+  let inFence = false
+  let blankCount = 0
+
+  return content
+    .trim()
+    .split('\n')
+    .filter(line => {
+      if (/^\s*(```|~~~)/.test(line)) {
+        inFence = !inFence
+      }
+
+      if (!inFence && !line.trim()) {
+        blankCount += 1
+        return blankCount <= 1
+      }
+
+      blankCount = 0
+      return true
+    })
+    .join('\n')
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizeMarkdown = (content: string): string => {
return content
.replace(/\n{3,}/g, '\n\n') // Collapse 3+ newlines to 2
.trim()
}
const normalizeMarkdown = (content: string): string => {
let inFence = false
let blankCount = 0
return content
.trim()
.split('\n')
.filter(line => {
if (/^\s*(
🤖 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 `@components/report-template.tsx` around lines 26 - 30, The normalization in
normalizeMarkdown is collapsing all repeated newlines before parsing, which also
alters fenced/preformatted markdown content and can corrupt code, logs, or
intentionally spaced blocks. Update normalizeMarkdown in report-template.tsx to
track whether the parser is inside a fenced code block and only collapse extra
blank lines when outside fences, keeping the existing downstream ReactMarkdown
rendering intact.

Comment on lines +35 to +61
const originalStyle = element.getAttribute('style') || ''
element.style.width = `${templateWidth}px`
element.style.position = 'relative'

const templateRect = element.getBoundingClientRect()
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'px',
format: 'a4'
})

const pdfWidth = pdf.internal.pageSize.getWidth()
const pdfHeight = pdf.internal.pageSize.getHeight()
const pdfScale = pdfWidth / templateWidth

const protectedRanges = Array.from(element.querySelectorAll('[data-pdf-nosplit]'))
.map(el => {
const rect = el.getBoundingClientRect()
return {
top: (rect.top - templateRect.top) * pdfScale,
bottom: (rect.bottom - templateRect.top) * pdfScale
}
})
.sort((a, b) => a.top - b.top)

// Restore original style
element.setAttribute('style', originalStyle)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Restore the mutated DOM style in a finally block.

If measurement or range derivation throws after Lines 36-37, the report DOM keeps the temporary inline width/position. Wrap the mutation in try/finally and remove the style attribute when it was originally absent.

Proposed fix
-const originalStyle = element.getAttribute('style') || ''
-element.style.width = `${templateWidth}px`
-element.style.position = 'relative'
+const originalStyle = element.getAttribute('style')
+let protectedRanges: Array<{ top: number; bottom: number }> = []
 
-const templateRect = element.getBoundingClientRect()
 const pdf = new jsPDF({
   orientation: 'portrait',
   unit: 'px',
   format: 'a4'
 })
 
 const pdfWidth = pdf.internal.pageSize.getWidth()
 const pdfHeight = pdf.internal.pageSize.getHeight()
 const pdfScale = pdfWidth / templateWidth
 
-const protectedRanges = Array.from(element.querySelectorAll('[data-pdf-nosplit]'))
-  .map(el => {
-    const rect = el.getBoundingClientRect()
-    return {
-      top: (rect.top - templateRect.top) * pdfScale,
-      bottom: (rect.bottom - templateRect.top) * pdfScale
-    }
-  })
-  .sort((a, b) => a.top - b.top)
-
-// Restore original style
-element.setAttribute('style', originalStyle)
+try {
+  element.style.width = `${templateWidth}px`
+  element.style.position = 'relative'
+
+  const templateRect = element.getBoundingClientRect()
+  protectedRanges = Array.from(element.querySelectorAll('[data-pdf-nosplit]'))
+    .map(el => {
+      const rect = el.getBoundingClientRect()
+      return {
+        top: (rect.top - templateRect.top) * pdfScale,
+        bottom: (rect.bottom - templateRect.top) * pdfScale
+      }
+    })
+    .sort((a, b) => a.top - b.top)
+} finally {
+  if (originalStyle === null) {
+    element.removeAttribute('style')
+  } else {
+    element.setAttribute('style', originalStyle)
+  }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const originalStyle = element.getAttribute('style') || ''
element.style.width = `${templateWidth}px`
element.style.position = 'relative'
const templateRect = element.getBoundingClientRect()
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'px',
format: 'a4'
})
const pdfWidth = pdf.internal.pageSize.getWidth()
const pdfHeight = pdf.internal.pageSize.getHeight()
const pdfScale = pdfWidth / templateWidth
const protectedRanges = Array.from(element.querySelectorAll('[data-pdf-nosplit]'))
.map(el => {
const rect = el.getBoundingClientRect()
return {
top: (rect.top - templateRect.top) * pdfScale,
bottom: (rect.bottom - templateRect.top) * pdfScale
}
})
.sort((a, b) => a.top - b.top)
// Restore original style
element.setAttribute('style', originalStyle)
const originalStyle = element.getAttribute('style')
let protectedRanges: Array<{ top: number; bottom: number }> = []
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'px',
format: 'a4'
})
const pdfWidth = pdf.internal.pageSize.getWidth()
const pdfHeight = pdf.internal.pageSize.getHeight()
const pdfScale = pdfWidth / templateWidth
try {
element.style.width = `${templateWidth}px`
element.style.position = 'relative'
const templateRect = element.getBoundingClientRect()
protectedRanges = Array.from(element.querySelectorAll('[data-pdf-nosplit]'))
.map(el => {
const rect = el.getBoundingClientRect()
return {
top: (rect.top - templateRect.top) * pdfScale,
bottom: (rect.bottom - templateRect.top) * pdfScale
}
})
.sort((a, b) => a.top - b.top)
} finally {
if (originalStyle === null) {
element.removeAttribute('style')
} else {
element.setAttribute('style', originalStyle)
}
}
🤖 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 `@lib/utils/report-generator.ts` around lines 35 - 61, The DOM style mutation
in report generation is not guaranteed to be restored if measurement or
protected range collection fails. In report-generator.ts, wrap the
`element.style.width` and `element.style.position` mutation around the
`getBoundingClientRect`/`querySelectorAll` logic in a `try/finally`, and restore
the original inline style in the `finally` block; if `originalStyle` was empty,
remove the `style` attribute instead of setting it back.

Comment on lines +100 to +105
// Only move the cut if the element starts after our current position (with small buffer)
// and fits on a single page.
if (straddle && straddle.top > currentPosition + 10) {
const elementHeight = straddle.bottom - straddle.top
if (elementHeight <= pdfHeight) {
effectiveCut = straddle.top

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don’t let the 10px buffer split protected elements.

A no-split element that starts within 10px of currentPosition and extends past nextPossibleCut is still split, even when elementHeight <= pdfHeight. Use the loop’s 0.5 progress threshold instead of a 10px layout buffer.

Proposed fix
-// Only move the cut if the element starts after our current position (with small buffer)
+// Only move the cut if it advances the cursor and the element fits on a single page.
 // and fits on a single page.
-if (straddle && straddle.top > currentPosition + 10) {
+if (straddle && straddle.top > currentPosition + 0.5) {
   const elementHeight = straddle.bottom - straddle.top
   if (elementHeight <= pdfHeight) {
     effectiveCut = straddle.top
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Only move the cut if the element starts after our current position (with small buffer)
// and fits on a single page.
if (straddle && straddle.top > currentPosition + 10) {
const elementHeight = straddle.bottom - straddle.top
if (elementHeight <= pdfHeight) {
effectiveCut = straddle.top
// Only move the cut if it advances the cursor and the element fits on a single page.
// and fits on a single page.
if (straddle && straddle.top > currentPosition + 0.5) {
const elementHeight = straddle.bottom - straddle.top
if (elementHeight <= pdfHeight) {
effectiveCut = straddle.top
🤖 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 `@lib/utils/report-generator.ts` around lines 100 - 105, The no-split handling
in report generation is still using the 10px layout buffer, which can split
protected elements that start close to the current position. Update the cut
logic in report-generator’s straddle handling to rely on the loop’s 0.5 progress
threshold instead of `currentPosition + 10`, while keeping the existing
`elementHeight <= pdfHeight` guard, so elements near the next cut are only moved
when they actually belong to the next page.

@ngoiyaeric

Copy link
Copy Markdown
Collaborator Author

10:31:15.734 Running build in Washington, D.C., USA (East) – iad1
10:31:15.735 Build machine configuration: 2 cores, 8 GB
10:31:15.847 Cloning github.com/QueueLab/QCX (Branch: pdf-boundary-aware-slicing-and-prose-cleanup-17795820845734913689, Commit: b733bb0)
10:31:16.804 Cloning completed: 955.000ms
10:31:19.317 Restored build cache from previous deployment (Dn3BbPLtq4NZvxA1PM5R7aLpudkc)
10:31:19.509 Running "vercel build"
10:31:19.532 Vercel CLI 54.17.2
10:31:19.901 Running "install" command: bun install...
10:31:19.935 [0.94ms] ".env"
10:31:19.941 bun install v1.3.12 (700fc117)
10:31:20.320 Saved lockfile
10:31:20.320
10:31:20.321 Checked 1324 installs across 1346 packages (no changes) [397.00ms]
10:31:20.325 Detected Next.js version: 15.3.8
10:31:20.326 Running "bun run build"
10:31:20.332 $ next build
10:31:21.126 ▲ Next.js 15.3.8
10:31:21.127 - Environments: .env
10:31:21.127
10:31:21.183 Creating an optimized production build ...
10:32:14.052 ✓ Compiled successfully in 48s
10:32:14.060 Linting and checking validity of types ...
10:32:21.756
10:32:21.757 ./components/chat.tsx
10:32:21.757 89:6 Warning: React Hook useEffect has a missing dependency: 'aiState.messages'. Either include it or remove the dependency array. react-hooks/exhaustive-deps
10:32:21.757
10:32:21.757 ./components/compare-slider.tsx
10:32:21.758 49:7 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.758 61:11 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.758
10:32:21.758 ./components/copilot-optimized.tsx
10:32:21.759 70:6 Warning: React Hook useEffect has missing dependencies: 'checkedOptions' and 'query'. Either include them or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setIsButtonDisabled' needs the current value of 'query'. react-hooks/exhaustive-deps
10:32:21.759
10:32:21.759 ./components/copilot.tsx
10:32:21.759 70:6 Warning: React Hook useEffect has missing dependencies: 'checkedOptions' and 'query'. Either include them or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setIsButtonDisabled' needs the current value of 'query'. react-hooks/exhaustive-deps
10:32:21.760
10:32:21.760 ./components/map/mapbox-map.tsx
10:32:21.760 470:6 Warning: React Hook useEffect has missing dependencies: 'mapData.cameraState', 'position?.latitude', and 'position?.longitude'. Either include them or remove the dependency array. react-hooks/exhaustive-deps
10:32:21.760
10:32:21.760 ./components/report-template.tsx
10:32:21.760 94:15 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.761 150:15 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.761 223:29 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.762 232:29 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.762
10:32:21.762 ./components/usage-view.tsx
10:32:21.763 69:15 Warning: Using <img> could result in slower LCP and higher bandwidth. Consider using <Image /> from next/image to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element @next/next/no-img-element
10:32:21.763
10:32:21.763 info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/app/api-reference/config/eslint#disabling-rules
10:32:34.124 Failed to compile.
10:32:34.125
10:32:34.125 ./components/report-template.tsx:135:60
10:32:34.125 Type error: Type '{ p: ({ children }: { children: React.ReactNode; }) => React.JSX.Element | null; }' is not assignable to type 'Components'.
10:32:34.126 Types of property 'p' are incompatible.
10:32:34.126 Type '({ children }: { children: React.ReactNode; }) => React.JSX.Element | null' is not assignable to type 'ElementType<ClassAttributes & HTMLAttributes & ExtraProps> | undefined'.
10:32:34.126 Type '({ children }: { children: React.ReactNode; }) => React.JSX.Element | null' is not assignable to type 'FunctionComponent<ClassAttributes & HTMLAttributes & ExtraProps>'.
10:32:34.126 Types of parameters '__0' and 'props' are incompatible.
10:32:34.127 Type 'ClassAttributes & HTMLAttributes & ExtraProps' is not assignable to type '{ children: ReactNode; }'.
10:32:34.127 Property 'children' is optional in type 'ClassAttributes & HTMLAttributes & ExtraProps' but required in type '{ children: ReactNode; }'.
10:32:34.127
10:32:34.127 133 |


10:32:34.127 134 |

10:32:34.128 > 135 |
10:32:34.128 | ^
10:32:34.128 136 | {normalizeMarkdown(aiSummary)}
10:32:34.128 137 |
10:32:34.128 138 |

10:32:34.172 Next.js build worker exited with code: 1 and signal: null
10:32:34.179 error: script "build" exited with code 1
10:32:34.195 Error: Command "bun run build" exited with 1

@charliecreates charliecreates 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.

Reviewed the latest changes, and I don't have actionable feedback to address.

- Update `MarkdownComponents` in `components/report-template.tsx` to make `children` optional.
- This ensures compatibility with `react-markdown`'s `Components` type and resolves the build failure.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@ngoiyaeric ngoiyaeric merged commit 647f648 into main Jun 26, 2026
4 checks passed
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.

1 participant