Skip to content

Conversation

@tac0turtle
Copy link
Contributor

When submissions contain many blobs (e.g., 14,000+), the page became unusable due to all blob hashes being rendered inline. This change adds a collapsible UI: submissions with >5 blobs show a preview of the first 3 with an expandable button to reveal the full list in a scrollable container.

Overview

When submissions contain many blobs (e.g., 14,000+), the page became
unusable due to all blob hashes being rendered inline. This change
adds a collapsible UI: submissions with >5 blobs show a preview of
the first 3 with an expandable button to reveal the full list in a
scrollable container.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@claude
Copy link
Contributor

claude bot commented Jan 29, 2026

Claude finished @tac0turtle's task in 1m 46s —— View job


Code Review Complete ✅

I've reviewed PR #3033 that adds collapsible blob list functionality to the DA Explorer. Overall, this is a well-implemented, focused feature that addresses a real usability issue. The code is clean, follows Go idioms, and the implementation is straightforward.


Strengths

  1. Solves a Real Problem: The collapsible UI effectively addresses the performance/usability issue with 14,000+ blob IDs rendering inline
  2. Clean Implementation: Simple, focused changes without over-engineering
  3. Progressive Enhancement: The feature gracefully handles both small (<5 blobs) and large (>5 blobs) datasets
  4. Good UX: Shows first 3 blobs with count of remaining items, scrollable expanded view
  5. Minimal Surface Area: Only 52 lines added across 2 files

🔍 Issues Found

1. JavaScript Bug: Button Text Not Initialized (pkg/rpc/server/templates/da_visualization.html:250)

Severity: Medium

The toggleBlobs function has a logic error. On first click, btn.dataset.expandText is undefined, so the button text becomes empty when collapsing:

btn.dataset.expandText = btn.textContent;  // Line 254: stores "+X more"
btn.textContent = 'Show less';             // Line 255: changes to "Show less"
// ... later on collapse:
btn.textContent = btn.dataset.expandText;  // Line 250: restores "+X more" ✅

However, on the first click to expand, line 250 tries to restore from btn.dataset.expandText which doesn't exist yet, resulting in empty text.

Fix: Initialize expandText on first click before using it:

if (isExpanded) {
    fullList.classList.remove('expanded');
    preview.style.display = 'inline';
    btn.textContent = btn.dataset.expandText || btn.textContent;  // Add fallback
} else {
    fullList.classList.add('expanded');
    preview.style.display = 'none';
    if (!btn.dataset.expandText) {  // Store original text on first expand
        btn.dataset.expandText = btn.textContent;
    }
    btn.textContent = 'Show less';
}

Fix this →


2. Template Function Type Safety (pkg/rpc/server/da_visualization.go:518-526)

Severity: Low - Enhancement Opportunity

The new template functions (subtract, lt, le) lack parameter validation. If called with invalid types in the template, they'll panic at runtime.

Current:

"subtract": func(a, b int) int {
    return a - b
},

Recommendation: While Go's template engine does some type checking, consider defensive validation for robustness:

"subtract": func(a, b int) (int, error) {
    return a - b, nil
},

Or keep simple functions as-is if template type safety is trusted (acceptable for internal use).


3. Potential XSS Risk (Low) (pkg/rpc/server/templates/da_visualization.html:199)

Severity: Low - Already Mitigated

The button text uses user-controlled data ({{subtract $numBlobs 3}}), but this is safe because:

  • ✅ Go's html/template auto-escapes output in HTML context
  • ✅ The value is computed server-side from trusted data
  • ✅ Not user-provided input

Status: No action needed, but good to note for review.


🎯 Code Quality Observations

Go Template Functions (pkg/rpc/server/da_visualization.go:518-526)

Pros:

  • Simple, focused implementations
  • Clear naming (subtract, lt, le)
  • Properly integrated into FuncMap

Considerations:

  • These are generic arithmetic helpers. If more template math is needed, consider a template utility package to avoid cluttering this file
  • Currently only used once each, which is fine for now

HTML/CSS/JavaScript (pkg/rpc/server/templates/da_visualization.html)

Pros:

  • Clean CSS with scoped classes
  • Semantic class names (.blob-ids-preview, .blob-ids-full)
  • Good hover states and visual feedback
  • Scrollable container prevents page overflow

Considerations:

  • JavaScript is inline in the template (acceptable for this small function, but consider extracting if more JS is added)
  • No keyboard accessibility (button works with Enter/Space by default, which is good)
  • Consider aria-expanded attribute for better accessibility (see below)

🚀 Performance & Edge Cases

Performance: ✅ Good

  • Rendering only 3 blob previews by default significantly improves page load
  • Scrollable container with max-height: 200px prevents DOM overflow
  • JavaScript toggle is lightweight (no framework needed)

Edge Cases Handled: ✅ Mostly Good

  • ✅ Empty blob lists ({{if .BlobIDs}})
  • ✅ Small blob lists (≤5 blobs show all)
  • ✅ Large blob lists (>5 blobs use collapsible UI)
  • ⚠️ Potential Issue: What happens with exactly 5 blobs? Current logic shows all 5 (via {{if le $numBlobs 5}}), but the button text would say "+2 more" which is confusing. Consider if the threshold should be > 5 or >= 5.

📋 Testing Recommendations

While this PR doesn't include tests (understandable for UI/visualization code), consider manual testing:

  1. Browser testing: Test toggleBlobs() in Chrome, Firefox, Safari
  2. Edge cases:
    • Submissions with 0 blobs
    • Submissions with exactly 5 blobs
    • Submissions with 14,000+ blobs (the original problem case)
  3. Multiple expansions: Click expand/collapse multiple times rapidly
  4. Multiple rows: Expand multiple rows simultaneously (should work independently)

🔒 Security Assessment

Overall: ✅ Secure

  • ✅ Uses html/template package which auto-escapes HTML
  • ✅ No user-controlled input in dangerous contexts
  • ✅ No SQL injection risk (no database queries in this code)
  • ✅ Blob IDs are hex-encoded server-side before rendering
  • ✅ JavaScript uses DOM manipulation, not eval() or innerHTML
  • ✅ No external resources loaded (no CDN dependencies)

🎨 Accessibility Suggestions (Optional Enhancement)

For better screen reader support, consider:

<button class="blob-toggle" onclick="toggleBlobs(this)" aria-expanded="false">
    +{{subtract $numBlobs 3}} more
</button>

And update JavaScript:

function toggleBlobs(btn) {
    const isExpanded = fullList.classList.contains('expanded');
    btn.setAttribute('aria-expanded', !isExpanded);
    // ... rest of function
}

Minor Polish Suggestions

  1. CSS: Consider adding transition for smoother expand/collapse:

    .blob-ids-full { 
        transition: all 0.2s ease-in-out; 
    }
  2. Button Icon: Consider using Unicode icons for better visual clarity:

    +{{subtract $numBlobs 3}} more  →  ▼ {{subtract $numBlobs 3}} more
    Show less                       →  ▲ Show less
  3. Consistency: The existing .blob-ids style at line 17 duplicates the one at line 30. Consider removing the duplicate or consolidating.


📊 Summary

Aspect Rating Notes
Code Quality ⭐⭐⭐⭐ Clean, focused implementation
Security ⭐⭐⭐⭐⭐ No vulnerabilities found
Performance ⭐⭐⭐⭐⭐ Solves the performance problem
Testing ⭐⭐⭐ No automated tests, needs manual testing
Accessibility ⭐⭐⭐ Works, but could add ARIA attributes
Edge Cases ⭐⭐⭐⭐ Handles most cases well

Recommendation: ✅ Approve with minor fix

The JavaScript button text bug should be fixed before merging (see Issue #1 above). Everything else is optional polish. The core functionality is solid and addresses the stated problem effectively.


📝 Files Reviewed

  • pkg/rpc/server/da_visualization.go (+11 lines) - Template functions
  • pkg/rpc/server/templates/da_visualization.html (+41 lines) - UI implementation

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @tac0turtle, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience of the Data Availability Explorer by introducing a collapsible display for blob IDs. Previously, pages with numerous blobs would become unresponsive due to excessive rendering. The new implementation addresses this by showing only a limited preview of blob IDs by default, with an interactive button to reveal the complete list, thus optimizing page load times and overall responsiveness.

Highlights

  • Collapsible Blob List: Implemented a collapsible UI for blob IDs in the DA Explorer to improve performance and usability when submissions contain a large number of blobs.
  • Conditional Display: Submissions with more than 5 blobs now display a preview of the first 3 blob IDs, with an option to expand and view the full list.
  • New Template Functions: Added 'subtract', 'lt' (less than), and 'le' (less than or equal to) functions to the Go template engine for enhanced conditional logic in the HTML.
  • Frontend Enhancements: Introduced new CSS styles and a JavaScript function ('toggleBlobs') to manage the interactive expansion and collapse of the blob ID lists.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 29, 2026

The latest Buf updates on your PR. Results from workflow CI / buf-check (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed⏩ skipped✅ passed✅ passedJan 29, 2026, 6:17 PM

@tac0turtle tac0turtle marked this pull request as ready for review January 29, 2026 18:17
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a collapsible UI for the blob list in the DA Explorer, which is a great improvement for usability when dealing with a large number of blobs. The implementation looks solid. I've added a couple of suggestions to improve the maintainability of the HTML template and the associated JavaScript. Specifically, I've recommended refactoring the JavaScript toggle function for conciseness and using a Go template define block to avoid duplicating the blob link HTML.

Comment on lines +188 to +206
{{if le $numBlobs 5}}
<div class="blob-ids">
{{$namespace := .Namespace}}
{{range .BlobIDs}}
<a href="/da/blob?id={{.}}&namespace={{$namespace}}" class="blob-link blob-id" title="Click to view blob details">{{slice . 0 8}}...</a>
{{end}}
</div>
{{else}}
<div class="blob-ids">
<span class="blob-ids-preview">
{{range $i, $id := .BlobIDs}}{{if lt $i 3}}<a href="/da/blob?id={{$id}}&namespace={{$namespace}}" class="blob-link blob-id" title="Click to view blob details">{{slice $id 0 8}}...</a>{{end}}{{end}}
</span>
<button class="blob-toggle" onclick="toggleBlobs(this)">+{{subtract $numBlobs 3}} more</button>
<div class="blob-ids-full">
{{range .BlobIDs}}
<a href="/da/blob?id={{.}}&namespace={{$namespace}}" class="blob-link blob-id" title="Click to view blob details">{{slice . 0 8}}...</a>
{{end}}
</div>
</div>
{{end}}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The HTML for rendering a blob link is duplicated in three places within this block (for <=5 blobs, for the preview of >5 blobs, and for the full list of >5 blobs). This could lead to inconsistencies if the link format needs to be changed in the future.

To improve maintainability, you could define a reusable template for the link using {{define}}. For example, you could add this somewhere in your template file (e.g., at the top):

{{define "blobLink"}}<a href="/da/blob?id={{.id}}&namespace={{.namespace}}" class="blob-link blob-id" title="Click to view blob details">{{slice .id 0 8}}...</a>{{end}}

Then, you can replace each instance of the <a> tag with a call to this template, for example:

{{range .BlobIDs}}{{template "blobLink" (dict "id" . "namespace" $namespace)}}{{end}}

This change would centralize the blob link's HTML, making it easier to update.

Comment on lines +241 to +257
function toggleBlobs(btn) {
const container = btn.parentElement;
const fullList = container.querySelector('.blob-ids-full');
const preview = container.querySelector('.blob-ids-preview');
const isExpanded = fullList.classList.contains('expanded');

if (isExpanded) {
fullList.classList.remove('expanded');
preview.style.display = 'inline';
btn.textContent = btn.dataset.expandText;
} else {
fullList.classList.add('expanded');
preview.style.display = 'none';
btn.dataset.expandText = btn.textContent;
btn.textContent = 'Show less';
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The toggleBlobs function can be made more concise by using classList.toggle() and simplifying the logic. The current implementation is correct, but a more streamlined version would be easier to read and maintain.

Suggested change
function toggleBlobs(btn) {
const container = btn.parentElement;
const fullList = container.querySelector('.blob-ids-full');
const preview = container.querySelector('.blob-ids-preview');
const isExpanded = fullList.classList.contains('expanded');
if (isExpanded) {
fullList.classList.remove('expanded');
preview.style.display = 'inline';
btn.textContent = btn.dataset.expandText;
} else {
fullList.classList.add('expanded');
preview.style.display = 'none';
btn.dataset.expandText = btn.textContent;
btn.textContent = 'Show less';
}
}
function toggleBlobs(btn) {
const container = btn.parentElement;
const fullList = container.querySelector('.blob-ids-full');
const preview = container.querySelector('.blob-ids-preview');
const isNowExpanded = fullList.classList.toggle('expanded');
preview.style.display = isNowExpanded ? 'none' : 'inline';
if (isNowExpanded) {
btn.dataset.expandText = btn.textContent;
btn.textContent = 'Show less';
} else {
btn.textContent = btn.dataset.expandText;
}
}

@codecov
Copy link

codecov bot commented Jan 29, 2026

Codecov Report

❌ Patch coverage is 0% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.33%. Comparing base (30a3e24) to head (fd8ee60).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/rpc/server/da_visualization.go 0.00% 11 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3033      +/-   ##
==========================================
- Coverage   55.38%   55.33%   -0.06%     
==========================================
  Files         117      117              
  Lines       11674    11685      +11     
==========================================
  Hits         6466     6466              
- Misses       4483     4494      +11     
  Partials      725      725              
Flag Coverage Δ
combined 55.33% <0.00%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@tac0turtle tac0turtle merged commit 455b6c1 into main Jan 29, 2026
31 checks passed
@tac0turtle tac0turtle deleted the feat/collapsible-blob-ids branch January 29, 2026 19:58
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.

3 participants