mirror of
https://github.com/boostorg/website-v2.git
synced 2026-01-19 04:42:17 +00:00
831 lines
37 KiB
HTML
831 lines
37 KiB
HTML
{% extends "admin/library_report_base.html" %}
|
|
{% load countries humanize avatar_tags text_helpers %}
|
|
{% load get_modulo_item_tag %}
|
|
{% load split_tag %}
|
|
|
|
{% load static %}
|
|
{% block css %}
|
|
{{ block.super }}
|
|
<style>
|
|
{% include "includes/_css_variables.css" %}
|
|
body {
|
|
-webkit-print-color-adjust:exact !important;
|
|
print-color-adjust:exact !important;
|
|
}
|
|
.link-icons a:hover {
|
|
color: var(--primary-color);
|
|
}
|
|
|
|
.sponsor-message ul > li {
|
|
list-style: circle;
|
|
margin-left: 2rem;
|
|
}
|
|
.sponsor-message a,
|
|
#library_index li a,
|
|
ul.slack-channels li div a,
|
|
.new-libraries a {
|
|
color: rgb(2, 132, 199);
|
|
}
|
|
|
|
.sponsor-message a:hover,
|
|
#library_index li a:hover,
|
|
ul.slack-channels li div a:hover,
|
|
.new-libraries a:hover {
|
|
color: rgb(255, 159, 0);
|
|
}
|
|
.committee_members img {
|
|
filter: grayscale(1);
|
|
}
|
|
#top-committed-libraries-chart .apexcharts-xaxis-label:nth-child(odd) {
|
|
transform: translateY(-8px);
|
|
}
|
|
|
|
#top-committed-libraries-chart .apexcharts-xaxis-label:nth-child(even) {
|
|
transform: translateY(8px);
|
|
}
|
|
.sponsor_message_copy p {
|
|
padding-top: 1em;
|
|
padding-bottom: 1em;
|
|
}
|
|
.sponsor_message_copy p:first-child {
|
|
padding-top: 0;
|
|
}
|
|
#search_stats_map {
|
|
border-radius: 8px;
|
|
}
|
|
|
|
</style>
|
|
{% endblock css %}
|
|
{% block content %}
|
|
<script src="{% static 'js/highlight.js' %}"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jsvectormap/dist/jsvectormap.min.css" />
|
|
<script src="https://cdn.jsdelivr.net/npm/jsvectormap"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/jsvectormap/dist/maps/world.js"></script>
|
|
|
|
{% now "F j, Y" as today %}
|
|
{% with bg_color='' %}
|
|
<div>
|
|
<div class="pdf-page grid grid-cols-2 gap-x-4 items-center justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6.png' %}')">
|
|
<div class="flex flex-col h-full justify-between">
|
|
<div class="flex flex-col gap-y-2">
|
|
<h1 class="flex mb-0">
|
|
<img
|
|
class="mt-[3px]"
|
|
style="width:3.3rem; margin-right:.5rem;" src="{% static 'img/Boost_Symbol_Transparent.svg' %}"
|
|
>
|
|
<span class="font-bold">Boost</span> <span class="text-[2.75rem] self-end mb-[2px]">{{ report_configuration.display_name }}</span>
|
|
</h1>
|
|
<div class="flex gap-x-12 link-icons my-4 text-2xl justify-between">
|
|
{% include "includes/_social_icon_links.html" %}
|
|
</div>
|
|
<div class="mb-2" class="font-bold">{% firstof version.release_date today %}</div>
|
|
<div><span class="font-bold">{{ commit_count|intcomma }}</span> commit{{ commit_count|pluralize }} up through {{ report_configuration.display_name }}</div>
|
|
<div><span class="font-bold">{{ lines_added|intcomma }}</span> line{{ lines_added|pluralize }} added, <span class="font-bold">{{ lines_removed|intcomma }}</span> line{{ lines_removed|pluralize }} removed</div>
|
|
<div><span class="font-bold">{{ version_commit_count|intcomma }}</span> new commit{{ version_commit_count|pluralize }} in all library repositories</div>
|
|
<div><span class="font-bold">{{ commit_contributors_release_count }}</span> commit contributors, <span class="font-bold">{{ commit_contributors_new_count }}</span> new</div>
|
|
<div><span class="font-bold">{{ opened_issues_count|intcomma }}</span> issues opened, <span class="font-bold">{{ closed_issues_count|intcomma }}</span> closed</div>
|
|
<div><span class="font-bold">{{ mailinglist_total|intcomma }}</span> posts to the developer's mailing list</div>
|
|
<div><span class="font-bold">{{ mailinglist_contributor_release_count }}</span> unique mailing list users, <span class="font-bold">{{ mailinglist_contributor_new_count }}</span> new</div>
|
|
{% if added_library_count %}
|
|
<div><span class="font-bold">{{ added_library_count }}</span> librar{{ added_library_count|pluralize:"y,ies" }} added</div>
|
|
{% endif %}
|
|
{% if removed_library_count %}
|
|
<div><span class="font-bold">{{ removed_library_count }}</span> librar{{ removed_library_count|pluralize:"y,ies" }} removed</div>
|
|
{% endif %}
|
|
</div>
|
|
{% if downloads %}
|
|
<table class="p-0 m-0 mt-1 w-full text-xs text-left border-0 border-separate table-auto border-spacing-0 text-slate">
|
|
<tbody>
|
|
<tr>
|
|
<th scope="col"
|
|
colspan="2"
|
|
class="p-1 text-sm border border-b-0 border-gray-400 text-center">
|
|
Download Now!
|
|
</th>
|
|
</tr>
|
|
{% for os, download_files in downloads.items %}
|
|
{% for download in download_files %}
|
|
<tr>
|
|
{% if forloop.first %}
|
|
<th scope="row"
|
|
rowspan="{{ download_files|length }}"
|
|
class="p-2 h-14 whitespace-nowrap border border-r-0 {% if not forloop.parentloop.last %}border-b-0 {% endif %}border-gray-400 text-center">
|
|
<i class="fab fa-{% if os == 'Unix' %}linux{% else %}windows{% endif %}"></i> {{ os }}
|
|
</th>
|
|
{% endif %}
|
|
<td class="p-[.33rem] border {% if not forloop.last or not forloop.parentloop.last %}border-b-0 {% endif %}border-gray-400">
|
|
<a href="{{ download.url }}" class="text-sky-600 hover:text-orange">{{ download.display_name }}</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% endif %}
|
|
</div>
|
|
<div class="flex flex-col h-full justify-between">
|
|
|
|
{% if report_configuration.release_report_cover_image and report_configuration.release_report_cover_image.url %}
|
|
<img
|
|
class="max-h-[60%]"
|
|
src="{{ report_configuration.release_report_cover_image.url|strip_query_string }}"
|
|
alt="release report cover image"
|
|
>
|
|
{% endif %}
|
|
|
|
{% if contribution_box_graph %}
|
|
<div class="flex flex-col gap-y-4">
|
|
<span class="mx-auto">Commits from {{ contribution_box_graph.graph_start }} to {{ contribution_box_graph.graph_end }}</span>
|
|
<div class="flex gap-x-1 mx-auto">
|
|
{% for week in contribution_box_graph.weeks %}
|
|
<div class="flex flex-col gap-y-1">
|
|
<div class="h-4 relative">
|
|
{% ifchanged week.days.0.date.month %}
|
|
{% if forloop.counter0 != 0 %}
|
|
<div class="absolute top-0 left-[-10px] text-sm font-bold">
|
|
{{ week.days.0.date|date:"M" }}
|
|
</div>
|
|
{% endif %}
|
|
{% endifchanged %}
|
|
</div>
|
|
{% for day in week.days %}
|
|
<div
|
|
class="w-4 h-4 rounded-sm"
|
|
{% if day.date >= prior_version.release_date %}
|
|
style="background-color: {{ day.color }};"
|
|
{% endif %}
|
|
title="{{ day.count }} commit{{ day.count|pluralize }} on {{ day.date }}"
|
|
>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
<div class="flex gap-x-1 text-sm mx-auto">
|
|
<div class="mr-1"><span class="font-bold">0</span> commits</div>
|
|
{% for color in contribution_box_graph.colors %}
|
|
<div class="h-4 w-4 rounded-sm" style="background-color: {{ color }}">
|
|
</div>
|
|
{% endfor %}
|
|
<div class="ml-1"><span class="font-bold">{{ contribution_box_graph.max }}</span> commits</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if report_configuration.sponsor_message %}
|
|
<div id="fiscal_committee_page" class="pdf-page !p-8 {{ bg_color }} bg-gray-200 relative">
|
|
<h2 class="mt-0">From the Fiscal Sponsorship Committee</h2>
|
|
<div class="flex flex-col w-full h-[85%] sponsor-message relative">
|
|
<svg
|
|
class="absolute overflow-visible pointer-events-none z-10"
|
|
version="1.1"
|
|
id="bubble_background"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
xmlns:svg="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
id="bubble"
|
|
style="fill:#ffffff;fill-rule:evenodd;stroke-width:0.896533"
|
|
d="M 28.068153,0 H 471.93339 c 17.18711,0 28.0676,10.63409 28.0674,26.12903 l -8e-4,56.64968 c 0,16.63468 -9.6004,26.12907 -28.0674,26.12907 -144.5008,3.63566 -356.11545,0.75984 -445.23187,0 -15.3824,0 -26.70095,-10.79719 -26.70074,-26.12907 l 7.8e-4,-56.64968 c 1.8e-4,-13.27403 12.64918,-26.12903 28.06737,-26.12903 z"
|
|
/>
|
|
</svg>
|
|
<div class="sponsor_message_copy dynamic-text p-[30px] mr-24 absolute z-20 max-h-[400px]">{{ report_configuration.sponsor_message|safe|linebreaks }}</div>
|
|
<div class="committee_members flex flex-wrap mt-2 text-sm text-center absolute" style="">
|
|
{% for user in committee_members|dictsort:"display_name" %}
|
|
<figure class="w-32 m-2">
|
|
{% avatar user=user is_link=False image_size="w-32 h-32" icon_size="text-8xl" use_user_hq_image=True %}
|
|
<figcaption class="p-1">{{user.display_name}}</figcaption>
|
|
</figure>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="flex flex-col pdf-page items-center justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg3.png' %}')">
|
|
|
|
<div class="flex flex-col mb-4">
|
|
<h2 class="mx-auto my-1">Git activity for this release</h2>
|
|
<div class="mx-auto"><span class="font-bold">{{ version_commit_count|intcomma }}</span> Commit{{ version_commit_count|pluralize }} Across <span class="font-bold">{{ library_count }}</span> Repositories</div>
|
|
{% if global_contributors_new_count %}
|
|
<div class="mx-auto"><span class="font-bold">{{ global_contributors_new_count|intcomma }}</span> First-time Contributor{{ global_contributors_new_count|pluralize }}</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="flex gap-x-8 justify-around w-full">
|
|
<div class="px-4">
|
|
<div class="mx-auto mb-6">Top Contributors</div>
|
|
<div class="m-auto grid grid-cols-1 gap-2">
|
|
{% for author in top_contributors_release_overall %}
|
|
<div class="flex flex-row gap-y-2 w-40 items-center">
|
|
{% avatar commitauthor=author %}
|
|
<div class="w-full flex flex-col ml-2">
|
|
<div class="text-[0.8rem] font-semibold overflow-ellipsis overflow-hidden whitespace-nowrap w-full">
|
|
{{ author.display_name }}
|
|
</div>
|
|
<div class="text-[0.7rem]"><span class="font-bold">{{ author.commit_count }}</span> commit{{ author.commit_count|pluralize }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col justify-center">
|
|
<h3 class="mx-auto">Most Committed Libraries</h3>
|
|
<div id="top-committed-libraries-chart" class="w-full text-center"></div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="pdf-page flex {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6.png' %}');">
|
|
|
|
<div class="flex gap-x-8 w-full">
|
|
<div class="px-4">
|
|
<div class="mx-auto mb-6 mt-[4.75rem]">Top Contributors</div>
|
|
<div class="m-auto grid grid-cols-1 gap-2">
|
|
{% for item in mailinglist_counts %}
|
|
<div class="flex flex-row gap-y-2 w-40 items-center">
|
|
{% avatar commitauthor=item %}
|
|
<div class="w-full flex flex-col ml-2">
|
|
<div class="text-[0.8rem] font-semibold overflow-ellipsis overflow-hidden whitespace-nowrap w-full">
|
|
{{ item.display_name|default:item.name }}
|
|
</div>
|
|
<div class="text-[0.7rem]"><span class="font-bold">{{ item.total_count }}</span> post{{ item.total_count|pluralize }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-col">
|
|
<h2 class="mx-auto">Mailing List</h2>
|
|
<div class="mx-auto mb-4">
|
|
There were
|
|
{% if mailinglist_total %}
|
|
<span class="font-bold">{{ mailinglist_total|intcomma }}</span>
|
|
{% else %}
|
|
no
|
|
{% endif %}
|
|
mailing list post{{ mailinglist_total|pluralize }} in version {{ report_configuration.display_name }} and
|
|
<span class="font-bold">{{ mailinglist_contributor_release_count }}</span>
|
|
poster{{ mailinglist_contributor_release_count|pluralize }}
|
|
in this version. (<span class="font-bold">{{ mailinglist_contributor_new_count }}</span> New)
|
|
</div>
|
|
<div class="text-center my-2">Weekly mailing list posts from {{prior_version.release_date}} to {% firstof version.release_date today %} on the Boost Developers mailing list.</div>
|
|
<div id="release_post_stats" class="mt-10 mx-4"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pdf-page flex {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6.png' %}');">
|
|
<div class="flex flex-col h-full mx-auto w-full">
|
|
<h2 class="mx-auto mb-10">Mailing List New Subscribers</h2>
|
|
<div class="text-center my-2">Mailing list new subscribers from from {{prior_version.release_date}} to {% firstof version.release_date today %} on the Boost Developers mailing list.</div>
|
|
|
|
<div id="subscriptions_stats"></div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="pdf-page flex {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6.png' %}');">
|
|
<div class="flex flex-col h-full mx-auto w-full">
|
|
<h2 class="mx-auto mb-10">Mailing List Top 200 Most Frequently Used Words</h2>
|
|
<div class="flex flex-col flex-wrap gap-x-4 gap-y-1 text-xs h-5/6">
|
|
{% for word in mailinglist_wordcloud_frequencies %}
|
|
<div class="max-w-[10rem]">
|
|
{{ word }}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% if mailinglist_wordcloud_base64 %}
|
|
<div class="pdf-page flex {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6.png' %}');">
|
|
<div class="flex flex-col mx-auto">
|
|
<h2 class="mx-auto mb-10">Mailing List Word Cloud</h2>
|
|
<div class="flex mx-auto">
|
|
<img src="data:image/png;base64,{{ mailinglist_wordcloud_base64 }}" alt="Mailing List Word Cloud" class="w-full">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if slack %}
|
|
{% for slack_channel_group in slack_channels %}
|
|
<div class="pdf-page flex items-center justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg4-rev.png' %}');">
|
|
<div class="flex flex-col h-full mx-auto w-full">
|
|
{% if forloop.first %}
|
|
<h2 class="mx-auto">Slack Channels</h2>
|
|
{% endif %}
|
|
<ul class="flex flex-row flex-wrap mx-auto w-full flex-wrap text-sm slack-channels">
|
|
{% for channel in slack_channel_group %}
|
|
<li class="w-1/2 p-2">
|
|
<strong>#{{channel.name}}</strong>
|
|
{% if channel.purpose %}
|
|
<div class="mx-auto">{{channel.purpose|safe}}</div>
|
|
{% endif %}
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% for slack_group in slack %}
|
|
<div class="pdf-page flex justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg4-rev.png' %}');">
|
|
<div class="flex flex-col mx-auto">
|
|
<div class="flex gap-x-[6rem]">
|
|
{% for slack_item in slack_group %}
|
|
<div class="flex flex-col mx-auto gap-y-2 w-96">
|
|
<h2 class="my-2">#{{slack_item.channel.name}}</h2>
|
|
<div>
|
|
<div class="mx-auto">
|
|
<span class="font-bold">{{ slack_item.total|intcomma }}</span>
|
|
slack message{{ slack_item.total|pluralize }} in #{{ slack_item.channel.name }}
|
|
</div>
|
|
<div class="mx-auto">
|
|
<span class="font-bold">{{ slack_item.user_count }}</span>
|
|
{{ slack_item.user_count|pluralize:"person,people" }}
|
|
were active for this release. (<span class="font-bold">{{ slack_item.new_user_count }}</span> New)
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-x-2">
|
|
<div>
|
|
<div class="font-bold">
|
|
Top Contributors
|
|
</div>
|
|
<div class="m-auto grid grid-cols-1 gap-2 mt-4">
|
|
{% for item in slack_item.users %}
|
|
<div class="flex flex-row gap-y-2 w-40 items-center">
|
|
{% base_avatar image_url=item.image_48 name=item.real_name href=None %}
|
|
<div class="w-full flex flex-col ml-2">
|
|
<div class="text-[0.8rem] font-semibold overflow-ellipsis overflow-hidden whitespace-nowrap w-full">
|
|
{{ item.real_name }}
|
|
</div>
|
|
<div class="text-[0.7rem]"><span class="font-bold">{{ item.total }}</span> message{{ item.total|pluralize }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if search_wordcloud_base64 %}
|
|
<div class="pdf-page flex flex-col {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg3.png' %}');">
|
|
<h2 class="mx-auto mb-10">Website Searches</h2>
|
|
<div class="flex flex-col mx-auto">
|
|
<div class="flex flex-row w-full h-1/2 p-4">
|
|
<div id="search_stats_map" class="w-1/2"></div>
|
|
<div class="w-1/2">
|
|
<div><strong>{{ search_stats.total_searches }}</strong> website searches.</div>
|
|
<div class="my-2">
|
|
<div class="py-1">Top <strong>{{search_stats.top_countries|length}}</strong> countries:</div>
|
|
<ul>
|
|
{% for code, count in search_stats.top_countries %}
|
|
{% get_country code as country %}
|
|
<li>{{ country.name }}: <strong>{{ count }}</strong> search{{ count|pluralize:"es" }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="w-full h-1/2 p-4">
|
|
<div class="flex mx-auto">
|
|
<img src="data:image/png;base64,{{ search_wordcloud_base64 }}" alt="Search Word Cloud" class="w-full">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="pdf-page flex items-center justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6-rev.png' %}');">
|
|
<div class="flex flex-col h-full mx-auto w-full">
|
|
<h2 class="mx-auto">Updated Libraries</h2>
|
|
<ul id="library_index" class="flex flex-col flex-wrap gap-x-4 gap-y-2 text-xs h-5/6">
|
|
{% for library, in_version_library_data in library_index_libraries %}
|
|
{% if in_version_library_data %}
|
|
<li class="max-w-[10rem] flex gap-x-1 items-center">
|
|
{% if library.group == "great" %}
|
|
<i class="text-orange fa-solid fa-star"></i>
|
|
{% elif library.group == "good" %}
|
|
<i class="text-orange fa-regular fa-star"></i>
|
|
{% else %}
|
|
<i class="text-orange fa-regular fa-fw"></i>
|
|
{% endif %}
|
|
<a href="#library-{{library.display_name}}" class="font-semibold">{{ library.name }}</a>
|
|
</li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pdf-page flex items-center justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg6-rev.png' %}');">
|
|
<div class="flex flex-col h-full mx-auto w-full">
|
|
<h2 class="mx-auto">Other Libraries</h2>
|
|
<ul id="library_index" class="flex flex-col flex-wrap gap-x-4 gap-y-2 text-xs h-5/6">
|
|
{% for library, in_version_library_data in library_index_libraries %}
|
|
{% if not in_version_library_data %}
|
|
<li class="max-w-[10rem] flex gap-x-1 items-center">
|
|
{% if library.group == "great" %}
|
|
<i class="text-orange fa-solid fa-star"></i>
|
|
{% elif library.group == "good" %}
|
|
<i class="text-orange fa-regular fa-star"></i>
|
|
{% else %}
|
|
<i class="text-orange fa-regular fa-fw"></i>
|
|
{% endif %}
|
|
<span>{{ library.name }}</span>
|
|
</li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
{% if new_libraries %}
|
|
<div class="pdf-page flex items-center justify-items-center {{ bg_color }}" style="background-image: url('{% static 'img/release_report/bg3.png' %}');">
|
|
<div class="flex flex-col h-full mx-auto w-full">
|
|
<h2 class="mx-auto">New Libraries</h2>
|
|
{% for library in new_libraries %}
|
|
<div class="flex flex-row gap-x-4 mb-4 gap-y-2 new-libraries">
|
|
{% if library.graphic %}
|
|
<div class="max-w-[16rem]">
|
|
<img src="{{ library.graphic.url }}" alt="" />
|
|
</div>
|
|
{% endif %}
|
|
<div class="flex flex-col gap-y-2">
|
|
<div class="font-semibold text-lg">
|
|
{{ library.name }}
|
|
</div>
|
|
<div class="text-sm">
|
|
{{ library.description }}
|
|
</div>
|
|
<div class="text-sm">
|
|
<a href="{{ library.github_url }}">{{ library.github_url }}</a>
|
|
</div>
|
|
<div class="text-sm font-semibold">Contributors:</div>
|
|
<div class="flex flex-row flex-wrap gap-x-4 gap-y-2">
|
|
{% for author in library.authors.all %}
|
|
<div class="flex flex-row gap-y-2 w-30 items-center">
|
|
{% avatar user=author %}
|
|
<div class="w-full flex flex-col pl-2">
|
|
<div class="text-[0.8rem] font-semibold overflow-ellipsis overflow-hidden whitespace-nowrap w-full">
|
|
{{ author.display_name }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% with "img/release_report/bg1.png,img/release_report/bg4-rev.png,img/release_report/bg3-rev.png,img/release_report/bg1-rev.png,img/release_report/bg2.png,img/release_report/bg6-rev.png,img/release_report/bg3.png,img/release_report/bg4.png,img/release_report/bg5.png,img/release_report/bg6.png,img/release_report/bg2-rev.png" as bg_list_str %}
|
|
{% with bg_list=bg_list_str|split:"," %}
|
|
{% for batch in batched_library_data %}
|
|
{% with current_bg=bg_list|get_modulo_item:forloop.counter0 %}
|
|
<div class="pdf-page flex flex-col {{ bg_color }}" style="background-image: url('{% static current_bg %}')">
|
|
{% for item in batch %}
|
|
<div class="grid grid-cols-3 gap-x-8 w-full p-4 h-1/2" id="library-{{ item.library.display_name }}">
|
|
<div class="col-span-2 flex flex-col gap-y-4">
|
|
<div class="flex flex-col gap-y-4">
|
|
<h2 class="text-orange mb-1 mt-0">{{ item.library.display_name }}</h2>
|
|
<div>{{ item.library.description }}</div>
|
|
</div>
|
|
<div class="flex gap-x-8 items-center">
|
|
{% if item.library.graphic %}
|
|
<div class="max-w-[10rem]">
|
|
<img src="{{ item.library.graphic.url }}" alt="" />
|
|
</div>
|
|
{% endif %}
|
|
<div class="flex flex-col gap-y-1">
|
|
<div>
|
|
There
|
|
{{ item.version_count.commit_count|pluralize:"was,were" }}
|
|
<span class="font-bold">{{ item.version_count.commit_count }}</span>
|
|
commit{{ item.version_count.commit_count|pluralize }}
|
|
in release {{ report_configuration.display_name }}
|
|
</div>
|
|
{% with insertions=item.library_version.insertions deletions=item.library_version.deletions %}
|
|
<div>
|
|
<span class="font-bold">{{ insertions|intcomma }}</span> line{{ insertions|pluralize }} added, <span class="font-bold">{{ deletions|intcomma }}</span> line{{ deletions|pluralize }} removed
|
|
</div>
|
|
{% endwith %}
|
|
{% with count=item.new_contributors_count.count %}
|
|
{% if count >= 1 %}
|
|
<div>
|
|
There {{ count|pluralize:"was,were" }} <span class="font-bold">{{ count }}</span> new contributor{{ count|pluralize }} for this release!
|
|
</div>
|
|
{% endif %}
|
|
{% endwith %}
|
|
<div>
|
|
There {{ item.issues.opened|pluralize:"was,were" }} <span class="font-bold">{{ item.issues.opened }}</span> issue{{ item.issues.opened|pluralize }} opened
|
|
and {{ item.issues.closed|pluralize:"was,were" }} <span class="font-bold">{{ item.issues.closed }}</span> issue{{ item.issues.closed|pluralize }} closed
|
|
</div>
|
|
{% if item.deps.added or item.deps.removed %}
|
|
<div>
|
|
There {{ item.deps.added|length|pluralize:"was,were" }} <span class="font-bold">{{ item.deps.added|length }}</span> dependenc{{ item.deps.added|length|pluralize:"y,ies" }} added
|
|
and
|
|
<span class="font-bold">{{ item.deps.removed|length }}</span> dependenc{{ item.deps.removed|length|pluralize:"y,ies" }} removed
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="px-4">
|
|
<div class="mx-auto mb-6">Top Contributors</div>
|
|
<div class="m-auto grid grid-cols-1 gap-2">
|
|
{% for author in item.top_contributors_release %}
|
|
<div class="flex flex-row gap-y-2 w-40 items-center">
|
|
{% avatar commitauthor=author %}
|
|
<div class="w-full flex flex-col ml-2">
|
|
<div class="text-[0.8rem] font-semibold overflow-ellipsis overflow-hidden whitespace-nowrap w-full">
|
|
{{ author.display_name }}
|
|
</div>
|
|
<div class="text-[0.7rem]"><span class="font-bold">{{ author.commit_count }}</span> commit{{ author.commit_count|pluralize }}</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endwith %}
|
|
{% endfor %}
|
|
{% endwith %}
|
|
{% endwith %}
|
|
</div>
|
|
<script>
|
|
const generalGraphOptions = {
|
|
chart: {
|
|
height: 400,
|
|
type: 'bar',
|
|
foreColor: '#373d3f',
|
|
background: '#ffffff00',
|
|
toolbar: {
|
|
show: false,
|
|
},
|
|
zoom: {
|
|
enabled: false
|
|
},
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
borderRadius: 2,
|
|
dataLabels: {
|
|
position: 'top', // top, center, bottom
|
|
},
|
|
}
|
|
},
|
|
dataLabels: {
|
|
offsetY: -16,
|
|
enabled: true,
|
|
style: {
|
|
fontSize: '11px',
|
|
colors: ["rgb(49, 74, 87)"],
|
|
}
|
|
},
|
|
xaxis: {
|
|
position: 'bottom',
|
|
axisBorder: {
|
|
show: false
|
|
},
|
|
axisTicks: {
|
|
show: false
|
|
},
|
|
tooltip: {
|
|
enabled: true,
|
|
}
|
|
},
|
|
yaxis: {
|
|
axisBorder: {
|
|
show: true
|
|
},
|
|
axisTicks: {
|
|
show: true,
|
|
},
|
|
labels: {
|
|
show: true,
|
|
}
|
|
},
|
|
};
|
|
var committedLibrariesOptions = {
|
|
...generalGraphOptions,
|
|
series: [{
|
|
name: 'Commits',
|
|
data: [{% for library in top_libraries_for_version|slice:":5" %}{{library.commit_count}}, {% endfor %}]
|
|
}],
|
|
xaxis: {
|
|
type: "category",
|
|
categories: [{% for library in top_libraries_for_version|slice:":5" %} "{{ library.name }}", {% endfor %}],
|
|
labels: {
|
|
rotate: 0,
|
|
hideOverlappingLabels: false
|
|
}
|
|
},
|
|
};
|
|
const libraryCommitsChart = new ApexCharts(document.querySelector("#top-committed-libraries-chart"), committedLibrariesOptions);
|
|
libraryCommitsChart.render();
|
|
|
|
var mailingListPostsOptions = {
|
|
...generalGraphOptions,
|
|
series: [{
|
|
name: 'Posts',
|
|
data: {{ mailinglist_post_stats|safe }}
|
|
}],
|
|
axisTicks: {
|
|
show: true,
|
|
},
|
|
xaxis: {
|
|
type: "category",
|
|
title: {
|
|
text: "Calendar Week {{ mailinglist_charts_start_year }}"
|
|
},
|
|
labels: {
|
|
rotate: 0,
|
|
formatter: function (value) {
|
|
// Format is: "WEEK (YEAR)", e.g. "51 (24)"
|
|
const match = value.match(/^(\d+)\s+\((\d{2})\)$/);
|
|
if (match) {
|
|
const week = parseInt(match[1]);
|
|
const year = match[2];
|
|
return week === 1 ? `1 ('${year})` : `${week}`;
|
|
}
|
|
return value; // fallback if pattern doesn't match
|
|
}
|
|
}
|
|
},
|
|
yaxis: {
|
|
title: {
|
|
text: "Posts"
|
|
}
|
|
},
|
|
};
|
|
const mailingListPostsChart = new ApexCharts(document.querySelector("#release_post_stats"), mailingListPostsOptions);
|
|
mailingListPostsChart.render();
|
|
|
|
const newEntries = {{mailinglist_new_subscribers_stats|safe}};
|
|
var subscriptionsOptions = {
|
|
...generalGraphOptions,
|
|
series: [{
|
|
name: 'New Subscribers',
|
|
data: newEntries
|
|
}],
|
|
axisTicks: {
|
|
show: true,
|
|
},
|
|
xaxis: {
|
|
type: "numeric",
|
|
title: {
|
|
text: "Calendar Week {{ mailinglist_charts_start_year }}"
|
|
},
|
|
labels: {
|
|
rotate: 0,
|
|
formatter: function (value) {
|
|
// Format is: "WEEK (YEAR)", e.g. "51 (24)"
|
|
const match = value.match(/^(\d+)\s+\((\d{2})\)$/);
|
|
if (match) {
|
|
const week = parseInt(match[1]);
|
|
const year = match[2];
|
|
return week === 1 ? `1 (20${year})` : `${week}`;
|
|
}
|
|
return value; // fallback if pattern doesn't match
|
|
}
|
|
}
|
|
},
|
|
yaxis: {
|
|
title: {
|
|
text: "New Subscribers"
|
|
},
|
|
},
|
|
dataLabels: {
|
|
enabled: false
|
|
}
|
|
};
|
|
|
|
const subscriptionsChart = new ApexCharts(document.querySelector("#subscriptions_stats"), subscriptionsOptions);
|
|
subscriptionsChart.render();
|
|
|
|
|
|
// Use fitText to resize text to fit its container.
|
|
// Starts at MAX_FONT_SIZE and tries smaller sizes until it fits or hits MIN_FONT_SIZE.
|
|
const fitText = async () => {
|
|
for (const text of document.querySelectorAll('.dynamic-text')) {
|
|
const MAX_FONT_SIZE = 23;
|
|
const MIN_FONT_SIZE = 16;
|
|
// Start with a large font size
|
|
let fontSize = MAX_FONT_SIZE;
|
|
text.style.fontSize = fontSize + 'px';
|
|
var computedStyle = window.getComputedStyle(text);
|
|
const intRegex = /(\d+)/;
|
|
const paddingY = parseInt(
|
|
computedStyle.getPropertyValue('padding-top').match(intRegex)
|
|
) + parseInt(
|
|
computedStyle.getPropertyValue('padding-right').match(intRegex)
|
|
);
|
|
const paddingX = parseInt(
|
|
computedStyle.getPropertyValue('padding-bottom')
|
|
) + parseInt(
|
|
computedStyle.getPropertyValue('padding-left')
|
|
);
|
|
const usableHeight = text.clientHeight - paddingY;
|
|
const textHeight = text.scrollHeight - paddingY;
|
|
// Reduce font size until text fits container
|
|
while (textHeight > usableHeight && fontSize > MIN_FONT_SIZE) {
|
|
fontSize--;
|
|
text.style.fontSize = fontSize + 'px';
|
|
}
|
|
}
|
|
}
|
|
|
|
const adjustBubbleSize = (width, height, radius) => {
|
|
const bubbleSVG = document.querySelector('#bubble_background');
|
|
if (!bubbleSVG) return;
|
|
|
|
const bubblePath = document.querySelector('#bubble');
|
|
if (!bubblePath) return;
|
|
|
|
// Set SVG size and viewBox
|
|
const attrs = { width, height, viewBox: `0 0 ${width} ${height}` };
|
|
Object.entries(attrs).forEach(
|
|
([key, value]) => bubbleSVG.setAttribute(key, value)
|
|
);
|
|
bubblePath.setAttribute(
|
|
'd',
|
|
`M ${radius},0
|
|
H ${width - radius}
|
|
Q ${width},0 ${width},${radius}
|
|
V ${height - radius}
|
|
Q ${width},${height} ${width - radius},${height}
|
|
H ${radius}
|
|
Q 0,${height} 0,${height - radius}
|
|
V ${radius}
|
|
Q 0,0 ${radius},0 Z`
|
|
);
|
|
};
|
|
|
|
const drawBubble = async () => {
|
|
// determines the gap between the text and the sponsor avatars
|
|
const blockGap = 35;
|
|
/*
|
|
bubbleScalingAdjustment accounts for scaling of bubble with longer content, with
|
|
the bubble and the copy being different heights
|
|
*/
|
|
const bubbleScalingAdjustment = 1; // 1.15 when point path in use
|
|
const bubbleCommitteeSpacing = 10;
|
|
const copyTextAdjustment = -2;
|
|
const bubbleRadius = 25;
|
|
|
|
const cmtePage = document.querySelector(".sponsor-message");
|
|
const usableHeight = cmtePage.offsetHeight;
|
|
|
|
const sponsorMessage = document.querySelector('.sponsor_message_copy');
|
|
const committeeMembers = document.querySelector('.committee_members');
|
|
const bubbleSVG = document.querySelector('#bubble_background');
|
|
|
|
const msgHeight = sponsorMessage.offsetHeight;
|
|
const msgWidth = sponsorMessage.offsetWidth;
|
|
|
|
const datum = (usableHeight - (sponsorMessage.offsetHeight + committeeMembers.offsetHeight)) / 2;
|
|
sponsorMessage.style.top = `${datum + copyTextAdjustment}px`;
|
|
bubbleSVG.style.top = `${datum}px`;
|
|
committeeMembers.style.top = `${datum + blockGap + sponsorMessage.offsetHeight}px`;
|
|
adjustBubbleSize(msgWidth, msgHeight * bubbleScalingAdjustment, bubbleRadius);
|
|
};
|
|
|
|
const drawSearchStatsMap = async () => {
|
|
const countryData = {{ search_stats.country_stats|safe }};
|
|
const map = new jsVectorMap({
|
|
selector: '#search_stats_map',
|
|
map: 'world',
|
|
zoomButtons: false,
|
|
visualizeData: { scale: ['#e8f1ff', '#1a73e8'], values: countryData },
|
|
onRegionTooltipShow: function(event, tooltip, code) {
|
|
const countryName = tooltip.text();
|
|
const searchCount = countryData[code] || 0;
|
|
tooltip.text(`${countryName}: ${searchCount} searches`);
|
|
}
|
|
})
|
|
}
|
|
|
|
window.addEventListener('DOMContentLoaded', async () => {
|
|
await fitText();
|
|
await drawBubble();
|
|
await drawSearchStatsMap();
|
|
});
|
|
</script>
|
|
{% endwith %}
|
|
{% endblock content %}
|