Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@razzasid
Copy link
Contributor

@razzasid razzasid commented Mar 20, 2025

As mentioned in issue #3363, this feature adds an autocomplete suggestion box to the report page’s textarea, allowing users to reference GitHub issues by typing # followed by a number. The suggestion box fetches matching issues from the OWASP-BLT/BLT repository, supports keyboard navigation (Arrow Up/Down, Enter, Escape), and positions itself dynamically below the cursor across all lines. The implementation includes debouncing for API calls, responsive design, and proper cleanup of the suggestion box when deleting the hashtag or clicking outside.

Testing Video

2025-03-20.07-04-47.mp4

Summary by CodeRabbit

  • New Features

    • Introduced dynamic suggestion functionality in text inputs, offering real-time recommendations, keyboard navigation, and seamless integration on report pages.
  • Style

    • Enhanced visual styling for suggestion components, including clear hover, focus, and selection states with responsive adjustments.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2025

Walkthrough

The changes introduce a new suggestion box feature to the website. New CSS classes for the suggestion box and its items define visual styles, including responsive adjustments. The JavaScript file now includes event listeners on a textarea to handle input and key events, triggering debounced API calls to fetch issue suggestions and enabling keyboard navigation for selecting suggestions. Additionally, the report template has been updated to load the new JavaScript functionality.

Changes

File(s) Change Summary
website/static/css/.../style.css Added new CSS classes: .suggestion-box and .suggestion-item with styling rules for layout, focus, hover, and responsiveness via a media query.
website/static/js/issue.js Introduced issue suggestion functionality: added event listeners, debounced input handling, keyboard navigation (arrow keys, Enter, Escape), API fetching for suggestions, suggestion box creation, and methods to insert issue references into the textarea.
website/templates/report.html Inserted a new script tag in the after_js block to include the updated issue.js script for enabling the suggestion functionality on the report page.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant T as Textarea
    participant JS as Issue Suggestion Script
    participant API as GitHub API

    U->>T: Types in textarea (e.g., "#123")
    T->>JS: Trigger input/keydown event
    JS->>JS: Debounce and process input
    JS->>API: Request issue suggestions
    API-->>JS: Return suggestions data
    JS->>T: Display suggestion box with results
    U->>JS: Navigate and select suggestion (arrow keys/Enter)
    JS->>T: Insert issue reference into textarea
Loading

Suggested reviewers

  • DonnieBLT
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
website/static/js/issue.js (2)

276-340: Good suggestion box DOM creation and styling.

The suggestion box creation is well-implemented. Consider moving more of the inline styles to the external CSS file to maintain better separation of concerns.


378-378: Use optional chaining for Link header check.

The static analysis tool correctly suggests using optional chaining for more concise code.

-            hasMorePages = linkHeader && linkHeader.includes('rel="next"');
+            hasMorePages = linkHeader?.includes('rel="next"');
🧰 Tools
🪛 Biome (1.9.4)

[error] 378-378: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 270b3c8 and 748a196.

📒 Files selected for processing (3)
  • website/static/css/style.css (1 hunks)
  • website/static/js/issue.js (1 hunks)
  • website/templates/report.html (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
website/static/js/issue.js

[error] 378-378: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
  • GitHub Check: Analyze (python)
🔇 Additional comments (6)
website/templates/report.html (1)

322-322: LGTM: Script inclusion for issue suggestion feature.

The script integration for the issue.js file is correctly placed in the after_js block, which ensures it loads after other JavaScript dependencies.

website/static/css/style.css (1)

587-627: LGTM: Well-structured CSS for the suggestion box feature.

The CSS classes for the suggestion box are well-defined with appropriate styling for different states (hover, selected) and responsive design considerations for smaller screens.

One minor inconsistency to note is that the max-height property is duplicated in both the CSS (line 594) and JavaScript (line 302). Consider maintaining this property in one location to avoid potential inconsistencies during future updates.

website/static/js/issue.js (4)

172-192: LGTM: Well-structured initialization and event binding.

The code establishes proper event listeners and initializes necessary variables for the suggestion box feature. The use of a cache Map is a good performance optimization.


193-224: Debounced input handling looks good.

The implementation of debouncing for API requests is a good practice to prevent excessive API calls while typing. The validation of input to only trigger on numeric characters after a hash symbol is well thought out.


226-275: Keyboard navigation implementation is comprehensive.

The keyboard navigation implementation provides a good user experience with support for arrow keys, Enter for selection, and Escape to dismiss. The code also includes logic to load more results when reaching the end of the list.


407-681: Comprehensive UI utility functions.

The utility functions for UI manipulation, cursor positioning, and text insertion are well-implemented. The code properly escapes HTML to prevent XSS attacks and handles a variety of edge cases.

Two suggestions for future enhancement:

  1. Consider adding ARIA attributes to improve accessibility
  2. Implement a mechanism to clean up event listeners if this component is dynamically loaded/unloaded

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 20, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
website/static/js/issue.js (1)

367-369: 🛠️ Refactor suggestion

Hardcoded repository name should be configurable.

The repository name is hardcoded as 'OWASP-BLT/BLT', which reduces the reusability of this component.

Consider making this configurable by fetching it from a data attribute or a global configuration variable to improve maintainability.

- const url = `https://api.github.com/repos/OWASP-BLT/BLT/issues?state=all&per_page=${perPage}&page=${page}`;
+ // Get repository name from a data attribute or global variable
+ const repo = document.querySelector('meta[name="repository"]')?.content || 'OWASP-BLT/BLT';
+ const url = `https://api.github.com/repos/${repo}/issues?state=all&per_page=${perPage}&page=${page}`;
🧹 Nitpick comments (4)
website/static/js/issue.js (4)

308-336: Consider moving styles to an external CSS file.

Injecting styles directly into the document head works but isn't ideal for maintainability. Consider moving these styles to your project's CSS files.

- const style = document.createElement('style');
- style.textContent = `
-     .suggestion-box::-webkit-scrollbar {
-         display: none;
-     }
-     .suggestion-item.selected {
-         background-color: #f0f0f0;
-     }
-     .load-more {
-         text-align: center;
-         padding: 8px;
-         color: #0366d6;
-         cursor: pointer;
-         font-weight: bold;
-         background-color: #f6f8fa;
-         border-top: 1px solid #e1e4e8;
-     }
-     .load-more:hover {
-         background-color: #f0f0f0;
-     }
-     .loading {
-         text-align: center;
-         padding: 8px;
-         color: #666;
-         font-style: italic;
-     }
- `;
- document.head.appendChild(style);

These styles should be added to your main CSS file instead.


377-378: Use optional chaining for cleaner code.

Instead of using the logical AND operator, use optional chaining for a more concise and modern approach.

- hasMorePages = linkHeader && linkHeader.includes('rel="next"');
+ hasMorePages = linkHeader?.includes('rel="next"');
🧰 Tools
🪛 Biome (1.9.4)

[error] 377-377: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


394-401: Add user-visible error handling for API failures.

While errors are logged to the console, users won't know why suggestions aren't appearing when API calls fail. Consider adding a user-visible error message.

        } catch (error) {
            console.error('Error fetching issues:', error);
            if (!append) {
+               // Show error message to user
+               suggestionBox.innerHTML = '<div class="suggestion-error">Failed to load suggestions</div>';
+               suggestionBox.style.display = 'block';
+               positionSuggestionBox();
+               setTimeout(hideSuggestionBox, 3000); // Hide after 3 seconds
                hideSuggestionBox();
            } else {
                // Remove loading indicator if there was an error
                removeLoadingIndicator();
            }

356-357: Optimize API usage to prevent unnecessary data fetching.

Currently, you're requesting 30 issues per page from GitHub's API but only showing 5 filtered results. This could lead to unnecessary data transfer and potentially hit GitHub API rate limits sooner.

- const perPage = 30; // GitHub API default
+ const perPage = 10; // Smaller batch size to optimize data transfer

Additionally, consider adding a search parameter to filter by issue number directly in the API call:

- const url = `https://api.github.com/repos/OWASP-BLT/BLT/issues?state=all&per_page=${perPage}&page=${page}`;
+ // Use search API to filter by issue number directly
+ const url = query ? 
+   `https://api.github.com/search/issues?q=repo:OWASP-BLT/BLT+${query}+in:number&per_page=${perPage}&page=${page}` :
+   `https://api.github.com/repos/OWASP-BLT/BLT/issues?state=all&per_page=${perPage}&page=${page}`;

This way, GitHub will do the filtering for you before sending the response.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 748a196 and cd7b385.

📒 Files selected for processing (1)
  • website/static/js/issue.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
website/static/js/issue.js

[error] 377-377: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
  • GitHub Check: Analyze (python)
🔇 Additional comments (7)
website/static/js/issue.js (7)

176-191: Good initialization and event handler setup!

The code properly initializes all necessary state variables and sets up appropriate event listeners. The defensive check for textarea existence is a good practice.


194-224: Well-implemented debouncing for API calls!

The input handler efficiently:

  1. Extracts the text after a hashtag
  2. Checks for numeric queries only
  3. Implements a 250ms debounce to prevent excessive API calls
  4. Resets pagination when input changes

This is a good implementation that will prevent excessive API calls while providing a responsive user experience.


227-275: Good keyboard navigation implementation with progressive loading!

The keyboard navigation correctly handles arrow keys, Enter for selection, and Escape to dismiss. The smart loading of additional results when navigating to the bottom of the list is an excellent UX consideration.


478-483: Good XSS prevention through proper escaping!

Using escapeHTML when displaying user-generated content is a great security practice to prevent XSS attacks. Well done!


567-611: Excellent cursor positioning technique!

The implementation of getCursorCoordinates is clever and thorough. By creating a mirror of the textarea with the same styling and measuring the cursor position, you ensure proper suggestion box placement regardless of text wrapping or scroll position.


672-680: Complete HTML escaping implementation.

Your escapeHTML function properly escapes all necessary characters to prevent XSS attacks. This is a critical security practice when rendering user-generated content.


172-173:

Details

❓ Verification inconclusive

Consider adding a rate limiting check for GitHub API.

GitHub's API has rate limits that could affect this feature if heavily used. Consider checking the rate limit headers in the API responses and notifying users when limits are close to being reached.


🏁 Script executed:

#!/bin/bash
# Check GitHub API rate limits
curl -s https://api.github.com/rate_limit | jq '.resources.core'

Length of output: 159


GitHub API Rate Limiting Check Recommendation

The GitHub API exhibits strict rate limits (e.g., a limit of 60 requests per hour with current usage at 2 and 58 remaining). To guard against potential disruptions under heavy use, please consider implementing a check that:

  • Reads the rate limit headers (e.g., X-RateLimit-Remaining).
  • Notifies users or gracefully handles the situation when the remaining quota approaches a critical threshold.

Please ensure that this additional logic is incorporated into the issue suggestion functionality in website/static/js/issue.js (around lines 172–173).

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 20, 2025
@DonnieBLT
Copy link
Collaborator

This would be for the Bugs on BLT, not Github Issues - we used to call them issues but now they are bugs and github issues. There is an API you can use to get the BLT bugs (issues)

@razzasid
Copy link
Contributor Author

@coderabbitai could you please change api request instead of github API use OWSAP-BLT API to fetch the issues BLT

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain
flowchart TB
    A[Change API Endpoint for Issue Suggestions] --o B[Understand current GitHub API implementation]
    A --o C[Find OWASP-BLT API endpoint for bugs]
    A --o D[Modify fetchIssueSuggestions function]
    D --o E[Change API URL to OWASP-BLT endpoint]
    D --o F[Adjust response handling for BLT API structure]
    D --o G[Update issue display format in suggestion box]
Loading

@razzasid I'll help you modify the code to use OWASP-BLT API instead of GitHub API for fetching bugs/issues. After analyzing the codebase, I need to find the correct API endpoint for BLT bugs. Let's modify the fetchIssueSuggestions function in the issue.js file:

// Function to fetch issue suggestions from the API
function fetchIssueSuggestions(query, page = 1) {
    // Check if we have cached results for this query and page
    const cacheKey = `${query}_${page}`;
    if (issueCache.has(cacheKey)) {
        return Promise.resolve(issueCache.get(cacheKey));
    }

    // Fetch bugs from OWASP-BLT API
    const apiUrl = `/api/v1/bugs/?page=${page}&per_page=5&search=${query}`;
    
    return fetch(apiUrl)
        .then(response => {
            // Check for pagination information in the response
            const totalPages = response.headers.get('X-Total-Pages') || 1;
            hasMorePages = page < parseInt(totalPages, 10);
            return response.json();
        })
        .then(data => {
            // Process bugs data from OWASP-BLT API
            const bugs = data.results || data;
            
            // Cache the results
            issueCache.set(cacheKey, bugs);
            return bugs;
        })
        .catch(error => {
            console.error('Error fetching bug suggestions:', error);
            return [];
        });
}

// Function to display suggestions in the suggestion box
function displaySuggestions(suggestions) {
    // Clear any existing suggestions
    suggestionBox.innerHTML = '';
    
    if (suggestions.length === 0) {
        // If no suggestions, display a message
        const noResults = document.createElement('div');
        noResults.className = 'suggestion-item';
        noResults.textContent = 'No bugs found';
        suggestionBox.appendChild(noResults);
        return;
    }
    
    // Add each suggestion to the suggestion box
    suggestions.forEach((suggestion, index) => {
        const item = document.createElement('div');
        item.className = 'suggestion-item';
        if (index === selectedIndex) {
            item.classList.add('selected');
        }
        
        // Format the suggestion text (bug number + title)
        item.textContent = `#${suggestion.id} - ${suggestion.description.substring(0, 50)}${suggestion.description.length > 50 ? '...' : ''}`;
        
        // Store the full suggestion data as a data attribute
        item.dataset.suggestion = JSON.stringify(suggestion);
        
        // Add click event to handle selection
        item.addEventListener('click', function() {
            selectedIndex = index;
            insertIssueReference(suggestion.id, suggestion.description.substring(0, 50));
            hideSuggestionBox();
        });
        
        suggestionBox.appendChild(item);
    });
    
    // Add "Load more" option if there are more pages
    if (hasMorePages) {
        const loadMore = document.createElement('div');
        loadMore.className = 'suggestion-item';
        loadMore.textContent = 'Load more...';
        loadMore.addEventListener('click', function() {
            currentPage++;
            const query = textarea.value.substring(lastHashIndex + 1, cursorPosition);
            fetchIssueSuggestions(query, currentPage)
                .then(newSuggestions => {
                    // Append new suggestions to existing ones
                    allSuggestions = [...allSuggestions, ...newSuggestions];
                    displaySuggestions(allSuggestions);
                });
        });
        suggestionBox.appendChild(loadMore);
    }
}

Note: I've assumed the API endpoint is /api/v1/bugs/ and that bugs have id and description fields. You may need to adjust these according to the actual OWASP-BLT API structure. If you can provide more details about the API endpoint and response structure, I can refine the code further.


🏁 Script executed:

#!/bin/bash
# Displaying the issue.js file to understand the current implementation
cat website/static/js/issue.js

Length of output: 23088


🏁 Script executed:

#!/bin/bash
# Looking for API-related files or endpoints in the project
grep -r "api" --include="*.py" . | grep -i "bug\|issue"

Length of output: 6608


🏁 Script executed:

#!/bin/bash
# Looking for URL patterns related to bugs/issues API
grep -r "url\|path" --include="*.py" . | grep -i "api.*bug\|api.*issue"

Length of output: 4499


🏁 Script executed:

#!/bin/bash
# Looking for API routes in urls.py files
find . -name "urls.py" -exec grep -l "api" {} \; | xargs cat | grep -i "bug\|issue"

Length of output: 5496


🏁 Script executed:

#!/bin/bash
# Find API view classes for bugs/issues
find . -name "*.py" -exec grep -l "class.*Api" {} \; | xargs cat | grep -A 20 -B 5 -i "bug\|issue"

Length of output: 15392


🏁 Script executed:

#!/bin/bash
# Check for API endpoints in views.py or api.py files
find . -name "views.py" -o -name "api.py" | xargs grep -l "def" | xargs grep -i "bug\|issue"

Length of output: 7297


🏁 Script executed:

#!/bin/bash
# Let's look for API routes specifically focused on bugs
find . -name "urls.py" | xargs grep -l "bug" | xargs grep -A 5 -B 5 -i "api"

Length of output: 12121


@razzasid I'll help you modify the code to use the OWASP-BLT API instead of GitHub API for fetching bugs. Looking at your codebase, I can see that the appropriate endpoint would be `/api/v1/issues/` which is handled by the `IssueViewSet`.

Here's the modified code for the fetchIssueSuggestions function and related parts:

// Function to fetch issue suggestions from the API
async function fetchIssueSuggestions(query, page = 1, append = false) {
    // If the query changed while we were waiting, abort
    if (query !== currentSearch) return;

    // Check cache first
    const cacheKey = `${query}-${page}`;
    if (cache.has(cacheKey)) {
        const cachedData = cache.get(cacheKey);
        displaySuggestions(cachedData.bugs, append);
        hasMorePages = cachedData.hasMorePages;
        return;
    }

    try {
        if (!append) {
            // Show loading indicator if this is the first page
            displayLoadingIndicator();
        } else {
            // Show loading indicator at the bottom if loading more
            appendLoadingIndicator();
        }
        
        // Get bugs for the current page using OWASP-BLT API
        const url = `/api/v1/issues/?search=${query} &page =${page}`;
        const response = await fetch(url);
        
        if (!response.ok) throw new Error('API request failed');
        
        const data = await response.json();
        
        // Extract results and pagination info from the response
        const bugs = data.results || data;
        
        // Check for pagination info
        hasMorePages = data.next !== null && data.next !== undefined;
        
        // Cache the results with pagination info
        cache.set(cacheKey, {
            bugs: bugs,
            hasMorePages: hasMorePages
        });
        
        // Only display if this is still the current search
        if (query === currentSearch) {
            displaySuggestions(bugs, append);
        }
    } catch (error) {
        console.error('Error fetching bugs:', error);
        if (!append) {
            hideSuggestionBox();
        } else {
            // Remove loading indicator if there was an error
            removeLoadingIndicator();
        }
    } finally {
        isLoadingMore = false;
    }
}

// Display suggestions with improved positioning
function displaySuggestions(bugs, append = false) {
    if (!append) {
        // Clear previous suggestions
        suggestionBox.innerHTML = '';
    } else {
        // Remove loading indicator and load more button
        removeLoadingIndicator();
        removeLoadMoreButton();
    }
    
    if (!bugs.length && !append) {
        hideSuggestionBox();
        return;
    }

    if (!append) {
        // Reset selection state
        selectedIndex = -1;
        isKeyboardNavigating = false;
    }

    // Add suggestion items
    bugs.forEach(bug => {
        const div = document.createElement('div');
        div.className = 'suggestion-item';
        div.dataset.issueNumber = bug.id;
        
        // Use description instead of title for BLT bugs, and truncate if needed
        const bugDescription = bug.description || '';
        const truncatedDescription = bugDescription.length > 50 
            ? bugDescription.substring(0, 50) + '...' 
            : bugDescription;
            
        div.innerHTML = ` <strong>#${bug.id}</strong> : ${escapeHTML(truncatedDescription)}`;
        div.style.cssText = `
            padding: 8px 10px;
            cursor: pointer;
            border-bottom: 1px solid #eee;
        `;
        
        div.addEventListener('click', (e) = > {
            e.stopPropagation(); // Prevent document click from firing
            insertIssueReference(bug.id);
            hideSuggestionBox();
        });
        
        div.addEventListener('mouseover', () => {
            if (!isKeyboardNavigating) {
                const items = getSuggestionItems();
                items.forEach(item => item.classList.remove('selected'));
                div.classList.add('selected');
                selectedIndex = Array.from(items).indexOf(div);
            }
        });
        
        div.addEventListener('mouseout', () => {
            if (!isKeyboardNavigating) {
                div.classList.remove('selected');
            }
        });
        
        suggestionBox.appendChild(div);
    });

    // Add "Load more" button if there are more pages
    if (hasMorePages) {
        const loadMoreButton = document.createElement('div');
        loadMoreButton.className = 'load-more';
        loadMoreButton.textContent = 'Load more...';
        loadMoreButton.addEventListener('click', (e) => {
            e.stopPropagation(); // Prevent document click from firing
            loadMoreIssues();
        });
        suggestionBox.appendChild(loadMoreButton);
    }

    // Position the suggestion box
    positionSuggestionBox();
    
    // Show the suggestion box
    suggestionBox.style.display = 'block';
}

This implementation:

  1. Changes the API endpoint from GitHub to the OWASP-BLT API (/api/v1/issues/)
  2. Adjusts the pagination handling to use the standard Django REST Framework pagination structure
  3. Updates the suggestion display to use the bug's id and description instead of number and title
  4. Maintains all the existing functionality (keyboard navigation, position calculation, etc.)

You may need to adjust the exact endpoint URL or field names based on your specific API implementation. If you have more details about the API structure, I can refine this code further.

---

Details

✏️ Learnings added
Learnt from: razzasid
URL: https://github.com/OWASP-BLT/BLT/pull/4010

Timestamp: 2025-03-20T12:05:51.717Z
Learning: The OWASP-BLT project uses its own API for fetching bugs/issues rather than GitHub Issues API. The feature for suggesting issues should use the OWASP-BLT API endpoint instead of GitHub API.

Learnt from: razzasid
URL: https://github.com/OWASP-BLT/BLT/pull/4010

Timestamp: 2025-03-20T12:05:51.717Z
Learning: OWASP-BLT uses its own API for fetching bugs rather than GitHub Issues API. These bugs were previously called "issues" but are now referred to as "bugs" in the codebase. The appropriate endpoint to fetch bugs is `/api/v1/issues/` which is handled by the IssueViewSet.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2025

A summary of the edits CodeRabbit will include in a stacked pull request to this pull request:

  • We are going to update the fetchIssueSuggestions() function in website/static/js/issue.js so that it uses the OWASP-BLT API endpoint instead of the GitHub API. The change will update the request URL to /api/bugs/ , adjust the pagination logic to check the X-Total-Pages header, and process the returned JSON using data.results if available.

  • We are going to update the displaySuggestions() function in website/static/js/issue.js so that it correctly formats and handles bug suggestions. This update will display each bug’s id and a truncated version of its description instead of a GitHub issue’s number and title, and update the click event to use these new values.

  • ✅ Create PR with these edits

  • 📋 Get copyable edits

  • 🔄 Try planning different edits

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
website/static/js/issue.js (4)

371-371: Use optional chaining for safer header access.

The code should use optional chaining when accessing properties that might be undefined.

-const linkHeader = response.headers.get('Link');
+const linkHeader = response.headers?.get('Link');
🧰 Tools
🪛 Biome (1.9.4)

[error] 371-371: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


369-372: Enhance pagination handling with X-Total-Pages header.

The current pagination implementation relies on the Link header, but BLT API might use a different pagination strategy.

If the BLT API returns pagination information in different headers (like X-Total-Pages), consider updating the code:

// Check for pagination headers (if provided)
const linkHeader = response.headers?.get('Link');
-hasMorePages = linkHeader && linkHeader.includes('rel="next"');
+const totalPages = response.headers?.get('X-Total-Pages');
+hasMorePages = totalPages ? currentPage < parseInt(totalPages) : linkHeader && linkHeader.includes('rel="next"');
🧰 Tools
🪛 Biome (1.9.4)

[error] 371-371: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


387-396: Improve error handling for API failures.

The current error handling only logs to console and hides the suggestion box but doesn't provide user feedback.

} catch (error) {
    console.error('Error fetching issues:', error);
    if (!append) {
-       hideSuggestionBox();
+       suggestionBox.innerHTML = '<div class="suggestion-error">Failed to load suggestions</div>';
+       suggestionBox.style.display = 'block';
+       positionSuggestionBox();
    } else {
        removeLoadingIndicator();
    }
}

435-441: Consider adding a loading threshold for pagination.

The current implementation loads more issues only when the user reaches the last item, which might lead to a poor user experience if they need to arrow through many items.

Consider triggering the load when the user is approaching the end (e.g., 1-2 items before the end):

// Load more issues if we're at the bottom and there are more pages
-if (e.key === 'ArrowDown' && selectedIndex === items.length - 1 && hasMorePages && !isLoadingMore) {
+if (e.key === 'ArrowDown' && selectedIndex >= items.length - 2 && hasMorePages && !isLoadingMore) {
    loadMoreIssues();
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd7b385 and 32d951e.

📒 Files selected for processing (1)
  • website/static/js/issue.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
website/static/js/issue.js

[error] 371-371: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: Run Tests
  • GitHub Check: docker-test
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (7)
website/static/js/issue.js (7)

362-363: Update API endpoint to use BLT bugs instead of GitHub issues.

According to the PR objectives, this feature should reference bugs in the BLT system rather than GitHub issues. The current API endpoint (/api/v1/issues) might not be the correct one.

Confirm whether this endpoint returns bugs from the BLT system as required in the PR comments. You may need to update this to the specific BLT bugs API endpoint.


362-368: Repository name should be configurable.

The API endpoint hardcodes the repository, which reduces reusability.


558-603: Excellent cursor position calculation for suggestion box positioning.

The implementation for calculating cursor coordinates within a textarea is very well done. It creates a mirror element to accurately determine cursor position, considers whitespace and line breaks, and cleans up DOM elements properly.


226-275: Well-implemented keyboard navigation.

The keyboard navigation with arrow up/down for selection, enter for confirmation, and escape to dismiss is well implemented with proper event prevention and focus management.


194-224: Effectively implemented debouncing for API calls.

The implementation correctly uses debouncing for API calls with a 250ms delay, which will help prevent excessive server requests as the user types.


665-672: Good security practice for preventing XSS.

The escapeHTML function properly sanitizes user-generated content to prevent cross-site scripting attacks.


519-556: Great handling of viewport boundaries.

The code ensures the suggestion box stays within viewport boundaries by checking against window dimensions and repositioning when necessary.

@DonnieBLT DonnieBLT enabled auto-merge (squash) March 20, 2025 23:26
@DonnieBLT DonnieBLT merged commit 5053fd6 into OWASP-BLT:main Mar 20, 2025
10 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.

2 participants