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

Skip to content

Conversation

@swaparup36
Copy link
Contributor

@swaparup36 swaparup36 commented Mar 11, 2025

User description

Screenshot 2025-03-11 102926
Resolves #3897


PR Type

Enhancement


Description

  • Added statistical charts to the repository detail page.

  • Implemented backend logic to fetch and process GitHub activity data.

  • Introduced new Django template filters for JSON serialization.

  • Enhanced frontend with Chart.js integration for dynamic visualizations.


Changes walkthrough 📝

Relevant files
Enhancement
repo_detail.html
Added statistical charts and dynamic data visualization   

website/templates/projects/repo_detail.html

  • Added a new section for statistical charts.
  • Integrated dynamic data visualization using Chart.js.
  • Displayed metrics like issues, pull requests, and commits.
  • Added logic for conditional styling based on data trends.
  • +209/-0 
    custom_filters.py
    Added JSON serialization filter for templates                       

    website/templatetags/custom_filters.py

  • Added a new filter to_json for JSON serialization.
  • Ensured safe string marking for JSON output.
  • +9/-0     
    project.py
    Backend logic for fetching and processing GitHub activity data

    website/views/project.py

  • Added logic to fetch GitHub activity data using API.
  • Implemented concurrent data fetching for efficiency.
  • Processed data for metrics and chart visualization.
  • Integrated activity data into the context for templates.
  • +222/-0 

    Need help?
  • Type /help how to ... in the comments thread for any questions about PR-Agent usage.
  • Check out the documentation for more information.
  • @github-actions
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    🎫 Ticket compliance analysis 🔶

    3897 - Partially compliant

    Compliant requirements:

    • Add statistical charts to the repository detail page.
    • Implement backend logic to fetch and process GitHub activity data.
    • Enhance frontend with Chart.js integration for dynamic visualizations.
    • Introduce new Django template filters for JSON serialization.

    Non-compliant requirements:

    []

    Requires further human verification:

    • Verify the visual appearance and functionality of the charts on the repository detail page.
    • Confirm the accuracy of the data displayed in the charts.
    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 Security concerns

    Sensitive information exposure:
    The fetch_activity_data method uses a GitHub token for API requests. Ensure that the token is securely stored and not exposed in logs or error messages.

    ⚡ Recommended focus areas for review

    Performance Concern

    The fetch_activity_data method uses concurrent requests and processes a significant amount of data. Ensure that this does not lead to performance bottlenecks or API rate limit issues.

    def fetch_activity_data(self, owner, repo_name):
        """Fetch detailed activity data for charts"""
        end_date = timezone.now()
        start_date = end_date - timedelta(days=60)
        headers = {
            "Authorization": f"token {settings.GITHUB_TOKEN}",
            "Accept": "application/vnd.github.v3+json",
        }
        base_url = f"https://api.github.com/repos/{owner}/{repo_name}"
    
        def fetch_all_pages(url):
            results = []
            page = 1
            while True:
                response = requests.get(f"{url}&page={page}", headers=headers)
                if response.status_code != 200 or not response.json():
                    break
                results.extend(response.json())
                page += 1
                if "Link" not in response.headers or 'rel="next"' not in response.headers["Link"]:
                    break
            return results
    
        # Fetching data concurrently
        with concurrent.futures.ThreadPoolExecutor() as executor:
            futures = {
                "issues": executor.submit(
                    fetch_all_pages, f"{base_url}/issues?state=all&since={start_date.isoformat()}&per_page=100"
                ),
                "pulls": executor.submit(
                    fetch_all_pages, f"{base_url}/pulls?state=all&since={start_date.isoformat()}&per_page=100"
                ),
                "commits": executor.submit(
                    fetch_all_pages, f"{base_url}/commits?since={start_date.isoformat()}&per_page=100"
                ),
            }
    
            data = {}
            for key, future in futures.items():
                try:
                    data[key] = future.result()
                except Exception as e:
                    print(f"Error fetching {key}: {e}")
                    data[key] = []
    
        # Processing data for charts
        dates = [(end_date - timedelta(days=x)).strftime("%Y-%m-%d") for x in range(30)]
    
        # Defining time periods
        current_month_start = end_date - timedelta(days=30)
        previous_month_start = current_month_start - timedelta(days=30)
    
        def calculate_period_metrics(data, start_date, end_date):
            """Calculate metrics for a specific time period"""
            start_date = timezone.make_aware(datetime.combine(start_date, datetime.min.time()))
            end_date = timezone.make_aware(datetime.combine(end_date, datetime.max.time()))
    
            return {
                "issues_opened": len(
                    [
                        i
                        for i in data["issues"]
                        if i.get("created_at")
                        and start_date <= parse_date(i["created_at"]) <= end_date
                        and "pull_request" not in i
                    ]
                ),
                "issues_closed": len(
                    [
                        i
                        for i in data["issues"]
                        if i.get("closed_at")
                        and start_date <= parse_date(i["closed_at"]) <= end_date
                        and "pull_request" not in i
                    ]
                ),
                "prs_opened": len(
                    [
                        p
                        for p in data["pulls"]
                        if p.get("created_at") and start_date <= parse_date(p["created_at"]) <= end_date
                    ]
                ),
                "prs_closed": len(
                    [
                        p
                        for p in data["pulls"]
                        if p.get("closed_at") and start_date <= parse_date(p["closed_at"]) <= end_date
                    ]
                ),
                "commits": len(
                    [
                        c
                        for c in data["commits"]
                        if c.get("commit", {}).get("author", {}).get("date")
                        and start_date <= parse_date(c["commit"]["author"]["date"]) <= end_date
                    ]
                ),
            }
    
        # Calculating metrics for both periods
        current_metrics = calculate_period_metrics(data, current_month_start.date(), end_date.date())
        previous_metrics = calculate_period_metrics(data, previous_month_start.date(), current_month_start.date())
    
        # Calculating percentage changes
        def calculate_percentage_change(current, previous):
            """Calculates percentage change between two periods"""
            if previous == 0:
                return 100 if current > 0 else 0
            return ((current - previous) / previous) * 100
    
        def calculate_ratio(current, previous):
            if previous == 0:
                return 1 if current > 0 else 0
            return current / previous
    
        changes = {
            "issue_ratio_percentage_change": calculate_percentage_change(
                (calculate_ratio(current_metrics["issues_opened"], current_metrics["issues_closed"])),
                (calculate_ratio(previous_metrics["issues_opened"], previous_metrics["issues_closed"])),
            ),
            "issue_ratio_change": (calculate_ratio(current_metrics["issues_opened"], current_metrics["issues_closed"]))
            - (calculate_ratio(previous_metrics["issues_opened"], previous_metrics["issues_closed"])),
            "pr_percentage_change": calculate_percentage_change(
                current_metrics["prs_opened"], previous_metrics["prs_opened"]
            ),
            "pr_change": current_metrics["prs_opened"] - previous_metrics["prs_opened"],
            "commit_percentage_change": calculate_percentage_change(
                current_metrics["commits"], previous_metrics["commits"]
            ),
            "commit_change": current_metrics["commits"] - previous_metrics["commits"],
        }
    
        chart_data = {
            "issues_labels": dates,
            "issues_opened": [],
            "issues_closed": [],
            "pr_labels": dates,
            "pr_opened_data": [],
            "pr_closed_data": [],
            "commits_labels": dates,
            "commits_data": [],
            "pushes_data": [],
            "issue_ratio_change": round(changes["issue_ratio_change"], 2),
            "pr_change": changes["pr_change"],
            "commit_change": changes["commit_change"],
            "issue_ratio_percentage_change": round(changes["issue_ratio_percentage_change"], 2),
            "pr_percentage_change": round(changes["pr_percentage_change"], 2),
            "commit_percentage_change": round(changes["commit_percentage_change"], 2),
        }
    
        for date in dates:
            # Counting issues with safe null checks
            issues_opened = len(
                [
                    i
                    for i in data["issues"]
                    if i.get("created_at") and i["created_at"].startswith(date) and "pull_request" not in i
                ]
            )
    
            issues_closed = len(
                [
                    i
                    for i in data["issues"]
                    if i.get("closed_at") and i["closed_at"].startswith(date) and "pull_request" not in i
                ]
            )
    
            # Counting PRs with safe null checks
            prs_opened = len([p for p in data["pulls"] if p.get("created_at") and p["created_at"].startswith(date)])
    
            prs_closed = len([p for p in data["pulls"] if p.get("closed_at") and p["closed_at"].startswith(date)])
    
            # Counting commits with safe null checks
            day_commits = [
                c
                for c in data["commits"]
                if (
                    c.get("commit", {}).get("author", {}).get("date") and c["commit"]["author"]["date"].startswith(date)
                )
            ]
            commits_count = len(day_commits)
            pushes_count = len(set(c.get("sha", "") for c in day_commits))
    
            # Adding to chart data
            chart_data["issues_opened"].append(issues_opened)
            chart_data["issues_closed"].append(issues_closed)
            chart_data["pr_opened_data"].append(prs_opened)
            chart_data["pr_closed_data"].append(prs_closed)
            chart_data["commits_data"].append(commits_count)
            chart_data["pushes_data"].append(pushes_count)
    
        return chart_data
    Data Validation

    Ensure that the data passed to the frontend (e.g., issues_labels, issues_opened) is properly validated to avoid rendering issues or JavaScript errors.

                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </section>
                    <!-- Statistics Charts -->
                    <section class="bg-white py-6 px-4 rounded-lg shadow-lg">
                        <h2 class="text-pink-500 font-bold text-lg">{{ repo.contributor_count|intcomma }} Contributions in the Last 30 Days</h2>
                        <div class="grid grid-cols-3 gap-2 mt-4">
                            <div class="p-4 border rounded-lg">
                                <span class="text-blue-500 text-sm flex w-full items-center justify-start">
                                    <p class="mr-2" id="open-closed-issue-ratio"></p>
                                    <p>Opened/Closed Issue Ratio</p>
                                </span>
                                <span class="text-xs flex justify-between items-center mt-3">
                                    <p class="text-gray-400">{{ issue_ratio_change|floatformat:2 }} ({{ issue_ratio_percentage_change|floatformat:2 }})</p>
                                    <p class="{% if issue_ratio_change >= 0 %}text-green-500{% else %}text-red-500{% endif %} flex items-center">
                                        {% if issue_ratio_change >= 0 %}
                                            <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                                            </svg>
                                        {% else %}
                                            <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z" clip-rule="evenodd" />
                                            </svg>
                                        {% endif %}
                                        past month
                                    </p>
                                </span>
                            </div>
                            <div class="p-4 border rounded-lg">
                                <span class="text-purple-500 text-sm flex w-full items-center justify-start">
                                    <p class="mr-2">{{ repo.open_pull_requests|intcomma }}</p>
                                    <p>Pull Requests Opened</p>
                                </span>
                                <span class="text-xs flex justify-between items-center mt-3">
                                    <p class="text-gray-400">{{ pr_change|intcomma }} ({{ pr_percentage_change|floatformat:2 }})</p>
                                    <p class="{% if pr_change >= 0 %}text-green-500{% else %}text-red-500{% endif %} flex items-center">
                                        {% if pr_change >= 0 %}
                                            <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                                            </svg>
                                        {% else %}
                                            <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z" clip-rule="evenodd" />
                                            </svg>
                                        {% endif %}
                                        past month
                                    </p>
                                </span>
                            </div>
                            <div class="p-4 border rounded-lg">
                                <span class="text-blue-500 text-sm flex w-full items-center justify-start">
                                    <p class="mr-2">{{ repo.commit_count|intcomma }}</p>
                                    <p>Commits</p>
                                </span>
                                <span class="text-xs flex justify-between items-center mt-3">
                                    <p class="text-gray-400">{{ commit_change|intcomma }} ({{ commit_percentage_change|floatformat:2 }})</p>
                                    <p class="{% if commit_change >= 0 %}text-green-500{% else %}text-red-500{% endif %} flex items-center">
                                        {% if commit_change >= 0 %}
                                            <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M3.293 9.707a1 1 0 010-1.414l6-6a1 1 0 011.414 0l6 6a1 1 0 01-1.414 1.414L11 5.414V17a1 1 0 11-2 0V5.414L4.707 9.707a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                                            </svg>
                                        {% else %}
                                            <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                <path fill-rule="evenodd" d="M16.707 10.293a1 1 0 010 1.414l-6 6a1 1 0 01-1.414 0l-6-6a1 1 0 111.414-1.414L9 14.586V3a1 1 0 012 0v11.586l4.293-4.293a1 1 0 011.414 0z" clip-rule="evenodd" />
                                            </svg>
                                        {% endif %}
                                        past month
                                    </p>
                                </span>
                            </div>
                        </div>
                        <div class="grid grid-cols-3 gap-4 mt-6">
                            <div class="p-4 border rounded-lg">
                                <div class="flex items-center justify-start">
                                    <span class="p-2 rounded-full mr-2">
                                        <svg class="w-5 h-5 text-blue-500"
                                            fill="none"
                                            stroke="currentColor"
                                            viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                                        </svg>
                                    </span>
                                    <p class="text-blue-500">Issues</p>
                                </div>
                                <canvas id="issuesChart"></canvas>
                            </div>
                            <div class="p-4 border rounded-lg">
                                <div class="flex items-center justify-start">
                                    <span class="p-2 rounded-full">
                                        <svg class="w-5 h-5 text-purple-500"
                                             fill="none"
                                             stroke="currentColor"
                                             viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
                                        </svg>
                                    </span>
                                    <p class="text-purple-500">Pull Requests</p>
                                </div>
                                <canvas id="prChart"></canvas>
                            </div>
                            <div class="p-4 border rounded-lg">
                                <div class="flex items-center justify-start">
                                    <span class="p-2 rounded-full">
                                        <svg class="w-5 h-5 text-orange-500"
                                             fill="none"
                                             stroke="currentColor"
                                             viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
                                        </svg>
                                    </span>
                                    <p class="text-orange-500">Pushes & Commits</p>
                                </div>
                                <canvas id="commitsChart"></canvas>
                            </div>
                        </div>
                    </section>
                    <!-- Community Section -->
                    <section class="bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden">
                        <div class="p-6">
                            <div class="flex items-center justify-between mb-4">
                                <h2 class="text-xl font-bold text-gray-900 flex items-center">
                                    <svg class="w-6 h-6 text-red-500 mr-2"
                                         fill="currentColor"
                                         viewBox="0 0 20 20">
                                        <path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z" />
                                    </svg>
                                    Community
                                </h2>
                                <div class="refresh-container relative inline-flex">
                                    <button class="refresh-btn relative ml-2"
                                            data-section="community"
                                            onclick="refreshSection(this, 'community')"
                                            title="Refresh community data">
                                        <svg class="w-5 h-5 transition-opacity duration-300"
                                             fill="none"
                                             stroke="currentColor"
                                             viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                                        </svg>
                                    </button>
                                </div>
                            </div>
                            <div class="space-y-6">
                                <!-- Contributors Summary -->
                                <div class="flex items-center justify-between">
                                    <h3 class="text-lg font-semibold text-gray-900">Top Contributors</h3>
                                    <span class="px-3 py-1 bg-red-50 text-red-600 rounded-full text-sm font-medium"
                                          data-community="total-count">
                                        {{ repo.contributor_count|intcomma }} total contributors
                                    </span>
                                </div>
                                <!-- Top Contributors Grid -->
                                <div class="grid grid-cols-1 md:grid-cols-2 gap-4 contributors-grid">
                                    {% for contributor in top_contributors %}
                                        <div class="flex items-center gap-4 p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors group">
                                            <img src="{{ contributor.avatar_url }}"
                                                 width="30"
                                                 height="30"
                                                 alt="{{ contributor.name }}"
                                                 class="w-12 h-12 rounded-full border-2 border-white shadow-md group-hover:scale-110 transition-transform">
                                            <div class="flex-grow">
                                                <div class="font-medium text-gray-900">
                                                    {{ contributor.name }}
                                                    {% if contributor.verified %}<span class="ml-1 text-green-500" title="Verified Contributor"></span>{% endif %}
                                                </div>
                                                <div class="text-sm text-gray-500">{{ contributor.contributions|intcomma }} commits</div>
                                            </div>
                                            <a href="{{ contributor.github_url }}"
                                               target="_blank"
                                               class="p-2 text-gray-400 hover:text-gray-600">
                                                <svg class="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
                                                    <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
                                                </svg>
                                            </a>
                                        </div>
                                    {% endfor %}
                                </div>
                                <!-- Other Contributors Summary -->
                                {% if repo.contributor_count > 6 %}
                                    <div class="mt-4 p-4 bg-gray-50 rounded-lg border border-gray-200">
                                        <div class="flex items-center justify-between">
                                            <div class="flex -space-x-2">
                                                {% for contributor in repo.contributor.all|dictsortreversed:"contributions"|slice:"6:11" %}
                                                    <img src="{{ contributor.avatar_url }}"
                                                         width="20"
                                                         height="20"
                                                         alt="{{ contributor.name }}"
                                                         class="w-8 h-8 rounded-full border-2 border-white"
                                                         title="{{ contributor.name }} ({{ contributor.contributions }} contributions)">
                                                {% endfor %}
                                                {% if repo.contributor_count > 11 %}
                                                    <div class="w-8 h-8 rounded-full border-2 border-white bg-gray-100 flex items-center justify-center text-sm font-medium text-gray-600">
                                                        +{{ repo.contributor_count|add:"-11" }}
                                                    </div>
                                                {% endif %}
                                            </div>
                                            <a href="https://github.com/{{ repo.repo_url|cut:'https://github.com/' }}/graphs/contributors"
                                               target="_blank"
                                               class="text-red-600 hover:text-red-700 text-sm font-medium flex items-center gap-1">
                                                View all contributors
                                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
                                                </svg>
                                            </a>
                                        </div>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </section>
                    <!-- Contributor Statistics Section -->
                    <section class="bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden">
                        <div class="p-6">
                            <div class="flex items-center justify-between mb-6">
                                <h2 class="text-xl font-bold text-gray-900 flex items-center">
                                    <svg class="w-6 h-6 text-red-500 mr-2"
                                         fill="currentColor"
                                         viewBox="0 0 20 20">
                                        <path d="M5 3a2 2 0 012-2h6a2 2 0 012 2v11a2 2 0 01-2 2H7a2 2 0 01-2-2V3zm0 11V3h10v11H5zm1-9h8v2H6V5zm0 3h8v2H6V8zm0 3h4v2H6v-2z" />
                                    </svg>
                                    Contributor Statistics
                                </h2>
                                <div class="flex items-center gap-4">
                                    <!-- Add refresh button container -->
                                    <div class="refresh-container relative inline-flex">
                                        <button class="refresh-btn relative ml-2"
                                                data-section="contributor_stats"
                                                onclick="refreshSection(this, 'contributor_stats')"
                                                title="Refresh contributor statistics">
                                            <svg class="w-5 h-5 transition-opacity duration-300"
                                                 fill="none"
                                                 stroke="currentColor"
                                                 viewBox="0 0 24 24">
                                                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                                            </svg>
                                        </button>
                                    </div>
                                    <!-- Existing filter dropdown -->
                                    <select id="time-period-select"
                                            class="form-select rounded-lg border-gray-300 text-sm"
                                            onchange="updateContributorStats(this.value)">
                                        {% for value, label in time_period_options %}
                                            <option value="{{ value }}" {% if time_period == value %}selected{% endif %}>{{ label }}</option>
                                        {% endfor %}
                                    </select>
                                </div>
                            </div>
                            <!-- Statistics Table -->
                            <div class="overflow-x-auto contributor-stats-table">
                                <table class="min-w-full divide-y divide-gray-200">
                                    <thead>
                                        <tr class="bg-gray-50">
                                            <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Contributor</th>
                                            <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Commits</th>
                                            <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Issues Opened</th>
                                            <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Issues Closed</th>
                                            <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Pull Requests</th>
                                            <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Comments</th>
                                            <th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">Total Impact</th>
                                        </tr>
                                    </thead>
                                    <tbody class="bg-white divide-y divide-gray-200">
                                        {% for stat in contributor_stats %}
                                            <tr class="hover:bg-gray-50 transition-colors">
                                                <td class="px-4 py-4 whitespace-nowrap">
                                                    <div class="flex items-center">
                                                        <img class="h-8 w-8 rounded-full"
                                                             width="20"
                                                             height="20"
                                                             src="{{ stat.contributor.avatar_url }}"
                                                             alt="{{ stat.contributor.name }}">
                                                        <div class="ml-3">
                                                            <div class="text-sm font-medium text-gray-900">{{ stat.contributor.name }}</div>
                                                            <div class="text-sm text-gray-500">@{{ stat.contributor.github_id }}</div>
                                                        </div>
                                                    </div>
                                                </td>
                                                <td class="px-4 py-4 whitespace-nowrap text-center text-emerald-600 font-medium">
                                                    {{ stat.commits|default:0|intcomma }}
                                                </td>
                                                <td class="px-4 py-4 whitespace-nowrap text-center text-blue-600 font-medium">
                                                    {{ stat.issues_opened|default:0|intcomma }}
                                                </td>
                                                <td class="px-4 py-4 whitespace-nowrap text-center text-purple-600 font-medium">
                                                    {{ stat.issues_closed|default:0|intcomma }}
                                                </td>
                                                <td class="px-4 py-4 whitespace-nowrap text-center text-orange-600 font-medium">
                                                    {{ stat.pull_requests|default:0|intcomma }}
                                                </td>
                                                <td class="px-4 py-4 whitespace-nowrap text-center text-cyan-600 font-medium">
                                                    {{ stat.comments|default:0|intcomma }}
                                                </td>
                                                <td class="px-4 py-4 whitespace-nowrap text-center">
                                                    <div class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ stat.impact_level.class }}">
                                                        {{ stat.impact_level.text }}
                                                    </div>
                                                </td>
                                            </tr>
                                        {% empty %}
                                            <tr>
                                                <td colspan="7" class="px-4 py-8 text-center text-gray-500">No contributor statistics available for this period</td>
                                            </tr>
                                        {% endfor %}
                                    </tbody>
                                </table>
                                {% if is_paginated %}
                                    <div class="flex items-center justify-between px-4 py-3 border-t border-gray-200 sm:px-6">
                                        <div class="flex-1 flex items-center justify-between">
                                            <div>
                                                <p class="text-sm text-gray-700">
                                                    Showing
                                                    <span class="font-medium">{{ page_obj.start_index }}</span>
                                                    to
                                                    <span class="font-medium">{{ page_obj.end_index }}</span>
                                                    of
                                                    <span class="font-medium">{{ paginator.count }}</span>
                                                    contributors
                                                </p>
                                            </div>
                                            <div>
                                                <nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px">
                                                    {% if page_obj.has_previous %}
                                                        <button type="button"
                                                                class="pagination-link relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
                                                                data-page="{{ page_obj.previous_page_number }}">
                                                            Previous
                                                        </button>
                                                    {% endif %}
                                                    {% for i in page_obj.paginator.page_range %}
                                                        {% if page_obj.number == i %}
                                                            <span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-red-50 text-sm font-medium text-red-600">
                                                                {{ i }}
                                                            </span>
                                                        {% else %}
                                                            <button type="button"
                                                                    class="pagination-link relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50"
                                                                    data-page="{{ i }}">{{ i }}</button>
                                                        {% endif %}
                                                    {% endfor %}
                                                    {% if page_obj.has_next %}
                                                        <button type="button"
                                                                class="pagination-link relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
                                                                data-page="{{ page_obj.next_page_number }}">Next</button>
                                                    {% endif %}
                                                </nav>
                                            </div>
                                        </div>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </section>
                    <!-- Technical Details Section -->
                    <section class="bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden">
                        <div class="p-6">
                            <div class="flex items-center justify-between mb-6">
                                <h2 class="text-xl font-bold text-gray-900 flex items-center">
                                    <svg class="w-6 h-6 text-red-500 mr-2"
                                         fill="currentColor"
                                         viewBox="0 0 20 20">
                                        <path fill-rule="evenodd" d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z" clip-rule="evenodd" />
                                    </svg>
                                    Technical Overview
                                </h2>
                                <div class="refresh-container relative inline-flex">
                                    <button class="refresh-btn relative ml-2"
                                            data-section="technical"
                                            onclick="refreshSection(this, 'technical')"
                                            title="Refresh technical information">
                                        <svg class="w-5 h-5 transition-opacity duration-300"
                                             fill="none"
                                             stroke="currentColor"
                                             viewBox="0 0 24 24">
                                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
                                        </svg>
                                    </button>
                                </div>
                            </div>
                            <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                                <!-- Language and Stack -->
                                <div class="bg-gray-50 rounded-lg p-5 border border-gray-200">
                                    <h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center">
                                        <svg class="w-5 h-5 text-indigo-500 mr-2"
                                             fill="currentColor"
                                             viewBox="0 0 20 20">
                                            <path fill-rule="evenodd" d="M12.316 3.051a1 1 0 01.633 1.265l-4 12a1 1 0 11-1.898-.632l4-12a1 1 0 011.265-.633zM5.707 6.293a1 1 0 010 1.414L3.414 10l2.293 2.293a1 1 0 11-1.414 1.414l-3-3a1 1 0 010-1.414l3-3a1 1 0 011.414 0zm8.586 0a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 11-1.414-1.414L16.586 10l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
                                        </svg>
                                        Language & Stack
                                    </h3>
                                    <div class="space-y-3">
                                        <div class="flex items-center gap-2">
                                            <span class="text-gray-600 shrink-0">Primary Language:</span>
                                            <span class="font-medium text-gray-900 px-3 py-1 bg-white rounded-full shadow-sm border border-gray-200 truncate"
                                                  data-tech="primary_language">
                                                {{ repo.primary_language|default:"Not specified" }}
                                            </span>
                                        </div>
                                        <div class="flex items-center gap-2">
                                            <span class="text-gray-600 shrink-0">Repository Size:</span>
                                            <span class="font-medium text-gray-900 px-3 py-1 bg-white rounded-full shadow-sm border border-gray-200 truncate"
                                                  data-tech="size">{{ repo.size|filesizeformat }}</span>
                                        </div>
                                        <div class="flex items-start gap-2">
                                            <span class="text-gray-600 shrink-0 mt-1">License:</span>
                                            <div class="font-medium text-gray-900 px-3 py-1 bg-white rounded-lg shadow-sm border border-gray-200 flex-1 break-words"
                                                 data-tech="license">{{ repo.license|default:"Not specified" }}</div>
                                        </div>
                                    </div>
                                </div>
                                <!-- Release Information -->
                                <div class="bg-gray-50 rounded-lg p-5 border border-gray-200">
                                    <h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center">
                                        <svg class="w-5 h-5 text-green-500 mr-2"
                                             fill="currentColor"
                                             viewBox="0 0 20 20">
                                            <path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd" />
                                        </svg>
                                        Latest Release
                                    </h3>
                                    {% if repo.release_name or repo.release_datetime %}
                                        <div class="space-y-3">
                                            {% if repo.release_name %}
                                                <div class="flex justify-between items-center">
                                                    <span class="text-gray-600">Version</span>
                                                    <span class="font-medium text-gray-900 px-3 py-1 bg-white rounded-full shadow-sm border border-gray-200"
                                                          data-tech="release_name">{{ repo.release_name }}</span>
                                                </div>
                                            {% endif %}
                                            {% if repo.release_datetime %}
                                                <div class="flex justify-between items-center">
                                                    <span class="text-gray-600">Release Date</span>
                                                    <span class="font-medium text-gray-900 px-3 py-1 bg-white rounded-full shadow-sm border border-gray-200"
                                                          data-tech="release_date">
                                                        {{ repo.release_datetime|date:"M d, Y" }}
                                                    </span>
                                                </div>
                                            {% endif %}
                                            <div class="flex justify-between items-center">
                                                <span class="text-gray-600">Last Commit</span>
                                                <span class="font-medium text-gray-900 px-3 py-1 bg-white rounded-full shadow-sm border border-gray-200"
                                                      data-tech="last_commit_date">
                                                    {{ repo.last_commit_date|date:"M d, Y" }}
                                                </span>
                                            </div>
                                        </div>
                                    {% else %}
                                        <div class="text-gray-500 text-center py-4">No release information available</div>
                                    {% endif %}
                                </div>
                            </div>
                        </div>
                    </section>
                    <!-- Milestone Section -->
                    <section class="bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden">
                        <div class="p-6">
                            <div class="flex items-center justify-between mb-6">
                                <h2 class="text-xl font-bold text-gray-900 flex items-center">
                                    <svg class="w-6 h-6 text-red-500 mr-2"
                                         fill="currentColor"
                                         viewBox="0 0 20 20">
                                        <path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z" clip-rule="evenodd" />
                                    </svg>
                                    Milestones
                                </h2>
                            </div>
                            <div class="space-y-6">
                                {% if milestones %}
                                    {% for milestone in milestones %}
                                        <div class="bg-gray-50 rounded-lg border border-gray-200 p-4 hover:bg-gray-100 transition-colors duration-150">
                                            <div class="flex justify-between items-start mb-3">
                                                <div class="flex flex-row items-start gap-4">
                                                    <h3 class="text-lg font-semibold text-gray-900">{{ milestone.title }}</h3>
                                                    <!-- {% if milestone.description %}<p class="text-gray-600 mt-1">{{ milestone.description }}</p>{% endif %} -->
                                                </div>
                                                <div class="flex flex-row items-start gap-2">
                                                    <div class="text-xs text-gray-500 flex items-center pt-0.5">
                                                        <svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
                                                            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
                                                        </svg>
                                                        {{ milestone.created_at|slice:":10" }}
                                                    </div>
                                                    <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {% if milestone.state == 'open' %}bg-green-100 text-green-800{% else %}bg-gray-100 text-gray-800{% endif %} mb-1">
                                                        {{ milestone.state|title }}
                                                    </span>
                                                </div>
                                            </div>
                                            <div class="flex items-center justify-between mt-4">
                                                <!-- Progress Bar (Left Half) -->
                                                <div class="w-1/2 pr-4">
                                                    {% with total_issues=milestone.open_issues|add:milestone.closed_issues %}
                                                        {% if total_issues > 0 %}
                                                            {% widthratio milestone.closed_issues total_issues 100 as percentage %}
                                                            <div class="flex items-center">
                                                                <div class="w-full bg-gray-200 rounded-full h-3 mr-2 relative">
                                                                    <div class="bg-[#e74c3c] h-3 rounded-full absolute top-0 left-0 progress-bar"
                                                                         data-percentage="{{ percentage }}"></div>
                                                                </div>
                                                                <span class="text-sm font-medium text-gray-700">{{ percentage }}%</span>
                                                            </div>
                                                        {% else %}
                                                            <div class="flex items-center">
                                                                <div class="w-full bg-gray-200 rounded-full h-3 mr-2 relative">
                                                                    <div class="bg-blue-600 h-3 rounded-full absolute top-0 left-0 w-0"></div>
                                                                </div>
                                                                <span class="text-sm font-medium text-gray-700">0%</span>
                                                            </div>
                                                        {% endif %}
                                                    {% endwith %}
                                                </div>
                                                <!-- Issues Count and GitHub Link (Right Half) -->
                                                <div class="flex items-center justify-between w-1/2">
                                                    <div class="flex items-center text-sm text-gray-600 mr-3">
                                                        <svg class="w-4 h-4 mr-1 text-red-400"
                                                             fill="currentColor"
                                                             viewBox="0 0 20 20">
                                                            <path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z" />
                                                            <path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5z" clip-rule="evenodd" />
                                                        </svg>
                                                        {{ milestone.open_issues }} open / {{ milestone.closed_issues }} closed
                                                    </div>
                                                    <a href="{{ milestone.html_url }}"
                                                       target="_blank"
                                                       class="text-sm text-red-600 hover:text-red-800 flex items-center ">
                                                        View on GitHub
                                                        <svg class="w-4 h-4 ml-1" fill="currentColor" viewBox="0 0 20 20">
                                                            <path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd" />
                                                        </svg>
                                                    </a>
                                                </div>
                                            </div>
                                            {% if milestone.due_on %}
                                                <div class="mt-2 text-xs text-gray-500">
                                                    <svg class="w-3 h-3 mr-1 inline" fill="currentColor" viewBox="0 0 20 20">
                                                        <path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1z" clip-rule="evenodd" />
                                                    </svg>
                                                    Due: {{ milestone.due_on|slice:":10" }}
                                                </div>
                                            {% endif %}
                                        </div>
                                    {% endfor %}
                                    <!-- MILESTONE PAGINATION CONTROLS - ALWAYS VISIBLE -->
                                    {% if milestone_pagination.total_pages > 1 %}
                                        <div class="mt-8 border-t border-gray-200 pt-6">
                                            <div class="flex items-center justify-between px-4 py-3 sm:px-6">
                                                <div class="flex-1 flex items-center justify-between">
                                                    <div>
                                                        <p class="text-sm text-gray-700">
                                                            Showing
                                                            <span class="font-medium">milestone page {{ milestone_pagination.current_page }}</span>
                                                            of
                                                            <span class="font-medium">{{ milestone_pagination.total_pages }}</span>
                                                        </p>
                                                    </div>
                                                    <div>
                                                        <nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px">
                                                            {% if milestone_pagination.has_previous %}
                                                                <a href="?milestone_page={{ milestone_pagination.previous_page }}{% if time_period %}&time_period={{ time_period }}{% endif %}"
                                                                   class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
                                                                    <span class="sr-only">Previous</span>
                                                                    <svg class="h-5 w-5"
                                                                         xmlns="http://www.w3.org/2000/svg"
                                                                         viewBox="0 0 20 20"
                                                                         fill="currentColor"
                                                                         aria-hidden="true">
                                                                        <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
                                                                    </svg>
                                                                </a>
                                                            {% else %}
                                                                <span class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-gray-100 text-sm font-medium text-gray-400 cursor-not-allowed">
                                                                    <span class="sr-only">Previous</span>
                                                                    <svg class="h-5 w-5"
                                                                         xmlns="http://www.w3.org/2000/svg"
                                                                         viewBox="0 0 20 20"
                                                                         fill="currentColor"
                                                                         aria-hidden="true">
                                                                        <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
                                                                    </svg>
                                                                </span>
                                                            {% endif %}
                                                            {% for page_num in milestone_pagination.page_range %}
                                                                {% if page_num == milestone_pagination.current_page %}
                                                                    <span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-red-50 text-sm font-medium text-red-600">
                                                                        {{ page_num }}
                                                                    </span>
                                                                {% else %}
                                                                    <a href="?milestone_page={{ page_num }}{% if time_period %}&time_period={{ time_period }}{% endif %}"
                                                                       class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
                                                                        {{ page_num }}
                                                                    </a>
                                                                {% endif %}
                                                            {% endfor %}
                                                            {% if milestone_pagination.has_next %}
                                                                <a href="?milestone_page={{ milestone_pagination.next_page }}{% if time_period %}&time_period={{ time_period }}{% endif %}"
                                                                   class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
                                                                    <span class="sr-only">Next</span>
                                                                    <svg class="h-5 w-5"
                                                                         xmlns="http://www.w3.org/2000/svg"
                                                                         viewBox="0 0 20 20"
                                                                         fill="currentColor"
                                                                         aria-hidden="true">
                                                                        <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                                                                    </svg>
                                                                </a>
                                                            {% else %}
                                                                <span class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-gray-100 text-sm font-medium text-gray-400 cursor-not-allowed">
                                                                    <span class="sr-only">Next</span>
                                                                    <svg class="h-5 w-5"
                                                                         xmlns="http://www.w3.org/2000/svg"
                                                                         viewBox="0 0 20 20"
                                                                         fill="currentColor"
                                                                         aria-hidden="true">
                                                                        <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                                                                    </svg>
                                                                </span>
                                                            {% endif %}
                                                        </nav>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    {% endif %}
                                {% else %}
                                    <div class="bg-gray-50 rounded-lg border border-gray-200 p-6 text-center">
                                        <p class="text-gray-500">No milestones found for this repository.</p>
                                    </div>
                                {% endif %}
                            </div>
                        </div>
                    </section>
                </div>
                <!-- Sidebar -->
                <div class="space-y-8">
                    <!-- Related Repositories -->
                    <section class="bg-white rounded-xl shadow-lg border border-gray-200 overflow-hidden">
                        <div class="p-6">
                            <h2 class="text-xl font-bold text-gray-900 mb-6 flex items-center">
                                <svg class="w-6 h-6 text-red-500 mr-2"
                                     fill="currentColor"
                                     viewBox="0 0 24 24">
                                    <path d="M13 17h8a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2h-8a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2zm0-2V3h8v12h-8z" />
                                    <path d="M3 19h8a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2H3a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2zm0-2V7h8v10H3z" />
                                </svg>
                                Related Repositories
                            </h2>
                            <div class="space-y-4">
                                {% for related_repo in related_repos %}
                                    <a href="{% url 'repo_detail' related_repo.slug %}" class="group block">
                                        <div class="p-4 bg-gray-50 rounded-lg border-2 border-transparent hover:border-red-500 transition-all duration-200 hover:shadow-lg relative overflow-hidden">
                                            <!-- Gradient overlay on hover -->
                                            <div class="absolute inset-0 bg-gradient-to-r from-red-500/0 to-red-500/5 opacity-0 group-hover:opacity-100 transition-opacity">
                                            </div>
                                            <!-- Content -->
                                            <div class="relative">
                                                <!-- Header -->
                                                <div class="flex items-center justify-between mb-2">
                                                    <div class="flex items-center gap-3">
                                                        <h3 class="font-medium text-gray-900 group-hover:text-red-600 transition-colors">{{ related_repo.name }}</h3>
                                                        {% if related_repo.is_main %}
                                                            <span class="px-2 py-1 bg-green-100 text-green-...
    

    @github-actions
    Copy link
    Contributor

    PR Code Suggestions ✨

    @swaparup36
    Copy link
    Contributor Author

    @DonnieBLT I raised this PR again as the previous one contained some unwanted files and spaces. This one does not have that issue. And the working ss is also there

    @DonnieBLT DonnieBLT enabled auto-merge (squash) March 11, 2025 17:33
    @DonnieBLT
    Copy link
    Collaborator

    LGTM! Thank you!

    @DonnieBLT DonnieBLT disabled auto-merge March 11, 2025 17:38
    @DonnieBLT DonnieBLT merged commit fcdd30d into OWASP-BLT:main Mar 11, 2025
    9 of 10 checks passed
    @coderabbitai coderabbitai bot mentioned this pull request Mar 16, 2025
    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.

    add statistic charts to the repo detail page

    2 participants